diff --git a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicGenerateModeEnum.java b/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicGenerateModeEnum.java index 425e2bb8c..ad4b81b36 100644 --- a/yudao-module-ai/yudao-module-ai-api/src/main/java/cn/iocoder/yudao/module/ai/enums/music/AiMusicGenerateModeEnum.java +++ b/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, "歌词模式"); /** * 模式 diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.java index 0d1d71c1d..2fac7b367 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.java @@ -1,12 +1,10 @@ package cn.iocoder.yudao.module.ai.controller.admin.music; +import cn.hutool.core.util.ObjUtil; 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.music.vo.AiMusicPageReqVO; -import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicRespVO; -import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicUpdatePublicStatusReqVO; -import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiSunoGenerateReqVO; +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.*; import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; import cn.iocoder.yudao.module.ai.service.music.AiMusicService; import io.swagger.v3.oas.annotations.Operation; @@ -30,13 +28,39 @@ public class AiMusicController { @Resource private AiMusicService musicService; - // TODO @xin:一个接口,获得【我的】音乐分页,参考 获得【我的】聊天角色分页 来写;用于我自己生成的列表,和音乐广场 + @GetMapping("/my-page") + @Operation(summary = "获得【我的】音乐分页") + public CommonResult> getMusicMyPage(@Valid AiMusicPageReqVO pageReqVO) { + PageResult pageResult = musicService.getMusicMyPage(pageReqVO, getLoginUserId()); + return success(BeanUtils.toBean(pageResult, AiMusicRespVO.class)); + } - // TODO @xin:一个接口,删除【我的】音乐 + @Operation(summary = "删除【我的】音乐记录") + @DeleteMapping("/delete-my") + @Parameter(name = "id", required = true, description = "音乐编号", example = "1024") + public CommonResult deleteMusicMy(@RequestParam("id") Long id) { + musicService.deleteMusicMy(id, getLoginUserId()); + return success(true); + } - // TODO @xin:一个接口,获得【我的】音乐 + @GetMapping("/get-my") + @Operation(summary = "获取【我的】音乐") + @Parameter(name = "id", required = true, description = "音乐编号", example = "1024") + public CommonResult getMusicMy(@RequestParam("id") Long id) { + AiMusicDO music = musicService.getMusic(id); + if (music == null || ObjUtil.notEqual(getLoginUserId(), music.getUserId())) { + return success(null); + } + return success(BeanUtils.toBean(music, AiMusicRespVO.class)); + } - // TODO @xin:一个接口,修改【我的】音乐,目前只支持修改标题 + @PostMapping("/updateTitle-my") + @Operation(summary = "修改【我的】音乐 目前只支持修改标题") + @Parameter(name = "title", required = true, description = "音乐名称", example = "夜空中最亮的星") + public CommonResult updateMusicTitle(AiMusicUpdateTitleReqVO updateReqVO) { + musicService.updateMusicTitle(updateReqVO); + return success(true); + } @PostMapping("/generate") @Operation(summary = "音乐生成") @@ -44,7 +68,7 @@ public class AiMusicController { return success(musicService.generateMusic(getLoginUserId(), reqVO)); } - // ================ 绘图管理 ================ + // ================ 音乐管理 ================ @GetMapping("/page") @Operation(summary = "获得音乐分页") diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicRespVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicRespVO.java index 470592fff..8c7db3605 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicRespVO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicRespVO.java @@ -61,6 +61,9 @@ public class AiMusicRespVO { @Schema(description = "错误信息") private String errorMessage; + @Schema(description = "音乐时长") + private Double duration; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) private LocalDateTime createTime; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdateTitleReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdateTitleReqVO.java new file mode 100644 index 000000000..a5d272bca --- /dev/null +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdateTitleReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.ai.controller.admin.music.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - AI 音乐修改名称 Request VO") +@Data +public class AiMusicUpdateTitleReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583") + private Long id; + + @Schema(description = "音乐名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "夜空中最亮的星") + @NotNull(message = "音乐名称不能为空") + private String title; + +} \ No newline at end of file diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiSunoGenerateReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiSunoGenerateReqVO.java index 4f0859134..66b40e44a 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiSunoGenerateReqVO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiSunoGenerateReqVO.java @@ -17,24 +17,38 @@ public class AiSunoGenerateReqVO { private String platform; // 参见 AiPlatformEnum 枚举 /** - * 1. 描述模式:描述词 + 是否纯音乐 + 模型 TODO @xin:目前貌似描述词没弄对?看着不是 prompt 字段(也可能我弄错了)。可以微信再沟通下哈 - * 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型 TODO @xin:目前这块少传递了标题; + * 1. 描述模式:描述词 + 是否纯音乐 + 模型 + * 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型 */ - @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, - example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。") + @Schema(description = "歌词模式用:用于生成音乐音频的歌词提示", requiredMode = Schema.RequiredMode.NOT_REQUIRED, + example = """ + [Verse] + 阳光下奔跑 多么欢快 + 假期就要来 心都飞起来 + 朋友在一旁 笑声又灿烂 + 无忧无虑的 每一天甜蜜 + [Chorus] + 马上放假了 快来庆祝 + 一起去旅行 快去冒险 + 日子太短暂 别再等待 + 马上放假了 梦想起飞 + """) private String prompt; + @Schema(description = "描述模式用:用于生成音乐音频的描述", requiredMode = Schema.RequiredMode.NOT_REQUIRED, + example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。") + private String gptDescriptionPrompt; + @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 tags; diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java index 22e257034..56fd87704 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/music/AiMusicDO.java @@ -30,7 +30,7 @@ public class AiMusicDO extends BaseDO { /** * 用户编号 - * + *

* 关联 AdminUserDO 的 userId 字段 */ private Long userId; @@ -67,7 +67,7 @@ public class AiMusicDO extends BaseDO { /** * 生成模式 - * + *

* 枚举 {@link AiMusicGenerateModeEnum} */ private Integer generateMode; @@ -113,4 +113,10 @@ public class AiMusicDO extends BaseDO { */ private String errorMessage; + + /** + * 音乐时长 + */ + private Double duration; + } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/music/AiMusicMapper.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/music/AiMusicMapper.java index 8d41086b2..025f5e018 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/music/AiMusicMapper.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/music/AiMusicMapper.java @@ -32,4 +32,13 @@ public interface AiMusicMapper extends BaseMapperX { .orderByDesc(AiMusicDO::getId)); } + default PageResult selectPageByMy(AiMusicPageReqVO reqVO, Long userId) { + return selectPage(reqVO, new LambdaQueryWrapperX() + // 情况一:公开 + .eq(Boolean.TRUE.equals(reqVO.getPublicStatus()), AiMusicDO::getPublicStatus, reqVO.getPublicStatus()) + // 情况二:私有 + .eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiMusicDO::getUserId, userId) + .orderByAsc(AiMusicDO::getId)); + } + } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicService.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicService.java index d21cf0e0d..af8ed0a87 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicService.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicService.java @@ -1,9 +1,7 @@ package cn.iocoder.yudao.module.ai.service.music; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicPageReqVO; -import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicUpdatePublicStatusReqVO; -import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiSunoGenerateReqVO; +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.*; import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; import jakarta.validation.Valid; @@ -20,7 +18,7 @@ public interface AiMusicService { * 音乐生成 * * @param userId 用户编号 - * @param reqVO 请求参数 + * @param reqVO 请求参数 * @return 生成的音乐ID */ List generateMusic(Long userId, AiSunoGenerateReqVO reqVO); @@ -39,6 +37,13 @@ public interface AiMusicService { */ void updateMusicPublicStatus(@Valid AiMusicUpdatePublicStatusReqVO updateReqVO); + /** + * 更新音乐名称 + * + * @param updateReqVO 更新信息 + */ + void updateMusicTitle(@Valid AiMusicUpdateTitleReqVO updateReqVO); + /** * 删除AI 音乐 * @@ -46,6 +51,22 @@ public interface AiMusicService { */ void deleteMusic(Long id); + /** + * 删除【我的】音乐记录 + * + * @param id 音乐编号 + * @param userId 用户编号 + */ + void deleteMusicMy(Long id, Long userId); + + /** + * 获得AI 音乐 + * + * @param id 音乐编号 + * @return 音乐内容 + */ + AiMusicDO getMusic(Long id); + /** * 获得音乐分页 * @@ -54,4 +75,12 @@ public interface AiMusicService { */ PageResult getMusicPage(AiMusicPageReqVO pageReqVO); + /** + * 获得【我的】音乐分页 + * + * @param pageReqVO 分页查询 + * @param userId 用户编号 + * @return 音乐分页 + */ + PageResult getMusicMyPage(AiMusicPageReqVO pageReqVO, Long userId); } diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java index 99323b73f..fb56fb4b0 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/music/AiMusicServiceImpl.java @@ -2,16 +2,17 @@ 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.ObjUtil; 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; -import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicUpdatePublicStatusReqVO; -import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiSunoGenerateReqVO; +import cn.iocoder.yudao.module.ai.controller.admin.music.vo.*; 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; @@ -21,6 +22,7 @@ import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.IMAGE_NOT_EXISTS; import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.MUSIC_NOT_EXISTS; /** @@ -38,6 +40,9 @@ public class AiMusicServiceImpl implements AiMusicService { @Resource private AiMusicMapper musicMapper; + @Resource + private FileApi fileApi; + @Override public List 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.getGptDescriptionPrompt(), 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 buildMusicDOList(List 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) { // 校验存在 @@ -115,6 +103,14 @@ public class AiMusicServiceImpl implements AiMusicService { musicMapper.updateById(new AiMusicDO().setId(updateReqVO.getId()).setPublicStatus(updateReqVO.getPublicStatus())); } + @Override + public void updateMusicTitle(AiMusicUpdateTitleReqVO updateReqVO) { + // 校验存在 + validateMusicExists(updateReqVO.getId()); + // 更新 + musicMapper.updateById(new AiMusicDO().setId(updateReqVO.getId()).setTitle(updateReqVO.getTitle())); + } + @Override public void deleteMusic(Long id) { // 校验存在 @@ -123,10 +119,20 @@ public class AiMusicServiceImpl implements AiMusicService { musicMapper.deleteById(id); } - private void validateMusicExists(Long id) { - if (musicMapper.selectById(id) == null) { - throw exception(MUSIC_NOT_EXISTS); + @Override + public void deleteMusicMy(Long id, Long userId) { + // 1. 校验是否存在 + AiMusicDO music = validateMusicExists(id); + if (ObjUtil.notEqual(music.getUserId(), userId)) { + throw exception(IMAGE_NOT_EXISTS); } + // 2. 删除记录 + musicMapper.deleteById(id); + } + + @Override + public AiMusicDO getMusic(Long id) { + return musicMapper.selectById(id); } @Override @@ -134,4 +140,53 @@ public class AiMusicServiceImpl implements AiMusicService { return musicMapper.selectPage(pageReqVO); } + @Override + public PageResult getMusicMyPage(AiMusicPageReqVO pageReqVO, Long userId) { + return musicMapper.selectPageByMy(pageReqVO, userId); + } + + /** + * 构建 AiMusicDO 集合 + * + * @param musicList suno 音乐任务列表 + * @return AiMusicDO 集合 + */ + private List buildMusicDOList(List 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())).setDuration(musicData.duration()) + .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); + } + + /** + * 校验音乐是否存在 + * + * @param id 音乐编号 + * @return 音乐信息 + */ + private AiMusicDO validateMusicExists(Long id) { + AiMusicDO music = musicMapper.selectById(id); + if (music == null) { + throw exception(MUSIC_NOT_EXISTS); + } + return music; + } + } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/suno/api/SunoApi.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/suno/api/SunoApi.java index d998fdbfa..27d2fa498 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/suno/api/SunoApi.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/suno/api/SunoApi.java @@ -117,7 +117,7 @@ public class SunoApi { * @param prompt 用于生成音乐音频的提示 * @param tags 音乐风格 * @param title 音乐名称 - * @param mv 模型 + * @param model 模型 * @param waitAudio false 表示后台模式,仅返回音频任务信息,需要调用 get API 获取详细的音频信息。 * true 表示同步模式,API 最多等待 100s,音频生成完毕后直接返回音频链接等信息,建议在 GPT 等 agent 中使用。 * @param makeInstrumental 指示音乐音频是否为定制,如果为 true,则从歌词生成,否则从提示生成 @@ -127,7 +127,7 @@ public class SunoApi { String prompt, String tags, String title, - String mv, + String model, @JsonProperty("wait_audio") boolean waitAudio, @JsonProperty("make_instrumental") boolean makeInstrumental ) { @@ -136,12 +136,12 @@ public class SunoApi { this(prompt, null, null, null, false, false); } - public MusicGenerateRequest(String prompt, String mv, boolean makeInstrumental) { - this(prompt, null, null, mv, false, makeInstrumental); + public MusicGenerateRequest(String prompt, String model, boolean makeInstrumental) { + this(prompt, null, null, model, false, makeInstrumental); } - public MusicGenerateRequest(String prompt, String mv, String tags, String title) { - this(prompt, tags, title, mv, false, false); + public MusicGenerateRequest(String prompt, String model, String tags, String title) { + this(prompt, tags, title, model, false, false); } } @@ -162,6 +162,7 @@ public class SunoApi { * @param prompt 生成音乐音频的提示 * @param type 操作类型 * @param tags 音乐类型标签 + * @param duration 音乐时长 */ public record MusicData( String id, @@ -176,7 +177,8 @@ public class SunoApi { @JsonProperty("gpt_description_prompt") String gptDescriptionPrompt, String prompt, String type, - String tags + String tags, + Double duration ) { } diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 7a33f1980..de08d7965 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -201,8 +201,8 @@ yudao.ai: notify-url: http://java.nat300.top/admin-api/ai/image/midjourney/notify suno: enable: true -# base-url: https://suno-om0w1cy6e-status2xxs-projects.vercel.app - base-url: http://127.0.0.1:3001 + base-url: https://suno-55ishh05u-status2xxs-projects.vercel.app +# base-url: http://127.0.0.1:3001 --- #################### 芋道相关配置 ####################