mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 18:49:06 +08:00 
			
		
		
		
	| @ -15,8 +15,8 @@ import java.util.Arrays; | |||||||
| @Getter | @Getter | ||||||
| public enum AiMusicGenerateModeEnum implements IntArrayValuable { | public enum AiMusicGenerateModeEnum implements IntArrayValuable { | ||||||
|  |  | ||||||
|     LYRIC(1, "歌词模式"), |     DESCRIPTION(1, "描述模式"), | ||||||
|     DESCRIPTION(2, "描述模式"); |     LYRIC(2, "歌词模式"); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 模式 |      * 模式 | ||||||
|  | |||||||
| @ -1,12 +1,10 @@ | |||||||
| package cn.iocoder.yudao.module.ai.controller.admin.music; | 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.CommonResult; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.common.util.object.BeanUtils; | 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.*; | ||||||
| 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.dal.dataobject.music.AiMusicDO; | import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | ||||||
| import cn.iocoder.yudao.module.ai.service.music.AiMusicService; | import cn.iocoder.yudao.module.ai.service.music.AiMusicService; | ||||||
| import io.swagger.v3.oas.annotations.Operation; | import io.swagger.v3.oas.annotations.Operation; | ||||||
| @ -30,13 +28,39 @@ public class AiMusicController { | |||||||
|     @Resource |     @Resource | ||||||
|     private AiMusicService musicService; |     private AiMusicService musicService; | ||||||
|  |  | ||||||
|     // TODO @xin:一个接口,获得【我的】音乐分页,参考 获得【我的】聊天角色分页 来写;用于我自己生成的列表,和音乐广场 |     @GetMapping("/my-page") | ||||||
|  |     @Operation(summary = "获得【我的】音乐分页") | ||||||
|  |     public CommonResult<PageResult<AiMusicRespVO>> getMusicMyPage(@Valid AiMusicPageReqVO pageReqVO) { | ||||||
|  |         PageResult<AiMusicDO> 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<Boolean> 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<AiMusicRespVO> 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<Boolean> updateMusicTitle(AiMusicUpdateTitleReqVO updateReqVO) { | ||||||
|  |         musicService.updateMusicTitle(updateReqVO); | ||||||
|  |         return success(true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @PostMapping("/generate") |     @PostMapping("/generate") | ||||||
|     @Operation(summary = "音乐生成") |     @Operation(summary = "音乐生成") | ||||||
| @ -44,7 +68,7 @@ public class AiMusicController { | |||||||
|         return success(musicService.generateMusic(getLoginUserId(), reqVO)); |         return success(musicService.generateMusic(getLoginUserId(), reqVO)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // ================ 绘图管理 ================ |     // ================ 音乐管理 ================ | ||||||
|  |  | ||||||
|     @GetMapping("/page") |     @GetMapping("/page") | ||||||
|     @Operation(summary = "获得音乐分页") |     @Operation(summary = "获得音乐分页") | ||||||
|  | |||||||
| @ -61,6 +61,9 @@ public class AiMusicRespVO { | |||||||
|     @Schema(description = "错误信息") |     @Schema(description = "错误信息") | ||||||
|     private String errorMessage; |     private String errorMessage; | ||||||
|  |  | ||||||
|  |     @Schema(description = "音乐时长") | ||||||
|  |     private Double duration; | ||||||
|  |  | ||||||
|     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|     private LocalDateTime createTime; |     private LocalDateTime createTime; | ||||||
|  |  | ||||||
|  | |||||||
| @ -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; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -17,24 +17,38 @@ public class AiSunoGenerateReqVO { | |||||||
|     private String platform; // 参见 AiPlatformEnum 枚举 |     private String platform; // 参见 AiPlatformEnum 枚举 | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 1. 描述模式:描述词 + 是否纯音乐 + 模型 TODO @xin:目前貌似描述词没弄对?看着不是 prompt 字段(也可能我弄错了)。可以微信再沟通下哈 |      * 1. 描述模式:描述词 + 是否纯音乐 + 模型 | ||||||
|      * 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型 TODO @xin:目前这块少传递了标题; |      * 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型 | ||||||
|      */ |      */ | ||||||
|     @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |     @Schema(description = "生成模式 1.描述模式 2. 歌词模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||||
|     @NotNull(message = "生成模式不能为空") |     @NotNull(message = "生成模式不能为空") | ||||||
|     private Integer generateMode; // 参见 AiMusicGenerateModeEnum 枚举 |     private Integer generateMode; // 参见 AiMusicGenerateModeEnum 枚举 | ||||||
|  |  | ||||||
|     @Schema(description = "用于生成音乐音频的提示", requiredMode = Schema.RequiredMode.REQUIRED, |     @Schema(description = "歌词模式用:用于生成音乐音频的歌词提示", requiredMode = Schema.RequiredMode.NOT_REQUIRED, | ||||||
|             example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。") |             example = """ | ||||||
|  |                     [Verse] | ||||||
|  |                     阳光下奔跑 多么欢快 | ||||||
|  |                     假期就要来 心都飞起来 | ||||||
|  |                     朋友在一旁 笑声又灿烂 | ||||||
|  |                     无忧无虑的 每一天甜蜜 | ||||||
|  |                     [Chorus] | ||||||
|  |                     马上放假了 快来庆祝 | ||||||
|  |                     一起去旅行 快去冒险 | ||||||
|  |                     日子太短暂 别再等待 | ||||||
|  |                     马上放假了 梦想起飞 | ||||||
|  |                     """) | ||||||
|     private String prompt; |     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") |     @Schema(description = "是否纯音乐", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "true") | ||||||
|     private Boolean makeInstrumental; |     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 = "模型不能为空") |     @NotEmpty(message = "模型不能为空") | ||||||
|     private String modelVersion; // 参见 AiModelEnum 枚举 |     private String model; // 参见 AiModelEnum 枚举 | ||||||
|  |  | ||||||
|     @Schema(description = "音乐风格", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "[\"pop\",\"jazz\",\"punk\"]") |     @Schema(description = "音乐风格", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "[\"pop\",\"jazz\",\"punk\"]") | ||||||
|     private List<String> tags; |     private List<String> tags; | ||||||
|  | |||||||
| @ -30,7 +30,7 @@ public class AiMusicDO extends BaseDO { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 用户编号 |      * 用户编号 | ||||||
|      * |      * <p> | ||||||
|      * 关联 AdminUserDO 的 userId 字段 |      * 关联 AdminUserDO 的 userId 字段 | ||||||
|      */ |      */ | ||||||
|     private Long userId; |     private Long userId; | ||||||
| @ -67,7 +67,7 @@ public class AiMusicDO extends BaseDO { | |||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 生成模式 |      * 生成模式 | ||||||
|      * |      * <p> | ||||||
|      * 枚举 {@link AiMusicGenerateModeEnum} |      * 枚举 {@link AiMusicGenerateModeEnum} | ||||||
|      */ |      */ | ||||||
|     private Integer generateMode; |     private Integer generateMode; | ||||||
| @ -113,4 +113,10 @@ public class AiMusicDO extends BaseDO { | |||||||
|      */ |      */ | ||||||
|     private String errorMessage; |     private String errorMessage; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 音乐时长 | ||||||
|  |      */ | ||||||
|  |     private Double duration; | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -32,4 +32,13 @@ public interface AiMusicMapper extends BaseMapperX<AiMusicDO> { | |||||||
|                 .orderByDesc(AiMusicDO::getId)); |                 .orderByDesc(AiMusicDO::getId)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     default PageResult<AiMusicDO> selectPageByMy(AiMusicPageReqVO reqVO, Long userId) { | ||||||
|  |         return selectPage(reqVO, new LambdaQueryWrapperX<AiMusicDO>() | ||||||
|  |                 // 情况一:公开 | ||||||
|  |                 .eq(Boolean.TRUE.equals(reqVO.getPublicStatus()), AiMusicDO::getPublicStatus, reqVO.getPublicStatus()) | ||||||
|  |                 // 情况二:私有 | ||||||
|  |                 .eq(Boolean.FALSE.equals(reqVO.getPublicStatus()), AiMusicDO::getUserId, userId) | ||||||
|  |                 .orderByAsc(AiMusicDO::getId)); | ||||||
|  |     } | ||||||
|  |      | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,9 +1,7 @@ | |||||||
| package cn.iocoder.yudao.module.ai.service.music; | package cn.iocoder.yudao.module.ai.service.music; | ||||||
|  |  | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | 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.*; | ||||||
| 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.dal.dataobject.music.AiMusicDO; | import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | ||||||
| import jakarta.validation.Valid; | import jakarta.validation.Valid; | ||||||
|  |  | ||||||
| @ -39,6 +37,13 @@ public interface AiMusicService { | |||||||
|      */ |      */ | ||||||
|     void updateMusicPublicStatus(@Valid AiMusicUpdatePublicStatusReqVO updateReqVO); |     void updateMusicPublicStatus(@Valid AiMusicUpdatePublicStatusReqVO updateReqVO); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新音乐名称 | ||||||
|  |      * | ||||||
|  |      * @param updateReqVO 更新信息 | ||||||
|  |      */ | ||||||
|  |     void updateMusicTitle(@Valid AiMusicUpdateTitleReqVO updateReqVO); | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 删除AI 音乐 |      * 删除AI 音乐 | ||||||
|      * |      * | ||||||
| @ -46,6 +51,22 @@ public interface AiMusicService { | |||||||
|      */ |      */ | ||||||
|     void deleteMusic(Long id); |     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<AiMusicDO> getMusicPage(AiMusicPageReqVO pageReqVO); |     PageResult<AiMusicDO> getMusicPage(AiMusicPageReqVO pageReqVO); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得【我的】音乐分页 | ||||||
|  |      * | ||||||
|  |      * @param pageReqVO 分页查询 | ||||||
|  |      * @param userId    用户编号 | ||||||
|  |      * @return 音乐分页 | ||||||
|  |      */ | ||||||
|  |     PageResult<AiMusicDO> getMusicMyPage(AiMusicPageReqVO pageReqVO, Long userId); | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,16 +2,17 @@ package cn.iocoder.yudao.module.ai.service.music; | |||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.hutool.core.text.StrPool; | import cn.hutool.core.text.StrPool; | ||||||
|  | import cn.hutool.core.util.ObjUtil; | ||||||
| import cn.hutool.core.util.StrUtil; | 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.ai.core.model.suno.api.SunoApi; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.PageResult; | 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.*; | ||||||
| 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.dal.dataobject.music.AiMusicDO; | 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.dal.mysql.music.AiMusicMapper; | ||||||
| import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; | import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; | ||||||
| import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; | import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; | ||||||
|  | import cn.iocoder.yudao.module.infra.api.file.FileApi; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
| import lombok.extern.slf4j.Slf4j; | import lombok.extern.slf4j.Slf4j; | ||||||
| import org.springframework.stereotype.Service; | 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.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.convertList; | ||||||
| import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; | 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; | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.MUSIC_NOT_EXISTS; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -38,6 +40,9 @@ public class AiMusicServiceImpl implements AiMusicService { | |||||||
|     @Resource |     @Resource | ||||||
|     private AiMusicMapper musicMapper; |     private AiMusicMapper musicMapper; | ||||||
|  |  | ||||||
|  |     @Resource | ||||||
|  |     private FileApi fileApi; | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<Long> generateMusic(Long userId, AiSunoGenerateReqVO reqVO) { |     public List<Long> generateMusic(Long userId, AiSunoGenerateReqVO reqVO) { | ||||||
|         // 1. 调用 Suno 生成音乐 |         // 1. 调用 Suno 生成音乐 | ||||||
| @ -45,12 +50,12 @@ public class AiMusicServiceImpl implements AiMusicService { | |||||||
|         if (Objects.equals(AiMusicGenerateModeEnum.LYRIC.getMode(), reqVO.getGenerateMode())) { |         if (Objects.equals(AiMusicGenerateModeEnum.LYRIC.getMode(), reqVO.getGenerateMode())) { | ||||||
|             // 1.1 歌词模式 |             // 1.1 歌词模式 | ||||||
|             SunoApi.MusicGenerateRequest generateRequest = new SunoApi.MusicGenerateRequest( |             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); |             musicDataList = sunoApi.customGenerate(generateRequest); | ||||||
|         } else if (Objects.equals(AiMusicGenerateModeEnum.DESCRIPTION.getMode(), reqVO.getGenerateMode())) { |         } else if (Objects.equals(AiMusicGenerateModeEnum.DESCRIPTION.getMode(), reqVO.getGenerateMode())) { | ||||||
|             // 1.2 描述模式 |             // 1.2 描述模式 | ||||||
|             SunoApi.MusicGenerateRequest generateRequest = new SunoApi.MusicGenerateRequest( |             SunoApi.MusicGenerateRequest generateRequest = new SunoApi.MusicGenerateRequest( | ||||||
|                     reqVO.getPrompt(), reqVO.getModelVersion(), reqVO.getMakeInstrumental()); |                     reqVO.getGptDescriptionPrompt(), reqVO.getModel(), reqVO.getMakeInstrumental()); | ||||||
|             musicDataList = sunoApi.generate(generateRequest); |             musicDataList = sunoApi.generate(generateRequest); | ||||||
|         } else { |         } else { | ||||||
|             throw new IllegalArgumentException(StrUtil.format("未知生成模式({})", reqVO)); |             throw new IllegalArgumentException(StrUtil.format("未知生成模式({})", reqVO)); | ||||||
| @ -90,23 +95,6 @@ public class AiMusicServiceImpl implements AiMusicService { | |||||||
|         return streamingTask.size(); |         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 |     @Override | ||||||
|     public void updateMusicPublicStatus(AiMusicUpdatePublicStatusReqVO updateReqVO) { |     public void updateMusicPublicStatus(AiMusicUpdatePublicStatusReqVO updateReqVO) { | ||||||
|         // 校验存在 |         // 校验存在 | ||||||
| @ -115,6 +103,14 @@ public class AiMusicServiceImpl implements AiMusicService { | |||||||
|         musicMapper.updateById(new AiMusicDO().setId(updateReqVO.getId()).setPublicStatus(updateReqVO.getPublicStatus())); |         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 |     @Override | ||||||
|     public void deleteMusic(Long id) { |     public void deleteMusic(Long id) { | ||||||
|         // 校验存在 |         // 校验存在 | ||||||
| @ -123,10 +119,20 @@ public class AiMusicServiceImpl implements AiMusicService { | |||||||
|         musicMapper.deleteById(id); |         musicMapper.deleteById(id); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private void validateMusicExists(Long id) { |     @Override | ||||||
|         if (musicMapper.selectById(id) == null) { |     public void deleteMusicMy(Long id, Long userId) { | ||||||
|             throw exception(MUSIC_NOT_EXISTS); |         // 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 |     @Override | ||||||
| @ -134,4 +140,53 @@ public class AiMusicServiceImpl implements AiMusicService { | |||||||
|         return musicMapper.selectPage(pageReqVO); |         return musicMapper.selectPage(pageReqVO); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public PageResult<AiMusicDO> getMusicMyPage(AiMusicPageReqVO pageReqVO, Long userId) { | ||||||
|  |         return musicMapper.selectPageByMy(pageReqVO, userId); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 构建 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())).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; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -117,7 +117,7 @@ public class SunoApi { | |||||||
|      * @param prompt           用于生成音乐音频的提示 |      * @param prompt           用于生成音乐音频的提示 | ||||||
|      * @param tags             音乐风格 |      * @param tags             音乐风格 | ||||||
|      * @param title            音乐名称 |      * @param title            音乐名称 | ||||||
|      * @param mv               模型 |      * @param model            模型 | ||||||
|      * @param waitAudio        false 表示后台模式,仅返回音频任务信息,需要调用 get API 获取详细的音频信息。 |      * @param waitAudio        false 表示后台模式,仅返回音频任务信息,需要调用 get API 获取详细的音频信息。 | ||||||
|      *                         true 表示同步模式,API 最多等待 100s,音频生成完毕后直接返回音频链接等信息,建议在 GPT 等 agent 中使用。 |      *                         true 表示同步模式,API 最多等待 100s,音频生成完毕后直接返回音频链接等信息,建议在 GPT 等 agent 中使用。 | ||||||
|      * @param makeInstrumental 指示音乐音频是否为定制,如果为 true,则从歌词生成,否则从提示生成 |      * @param makeInstrumental 指示音乐音频是否为定制,如果为 true,则从歌词生成,否则从提示生成 | ||||||
| @ -127,7 +127,7 @@ public class SunoApi { | |||||||
|             String prompt, |             String prompt, | ||||||
|             String tags, |             String tags, | ||||||
|             String title, |             String title, | ||||||
|             String mv, |             String model, | ||||||
|             @JsonProperty("wait_audio") boolean waitAudio, |             @JsonProperty("wait_audio") boolean waitAudio, | ||||||
|             @JsonProperty("make_instrumental") boolean makeInstrumental |             @JsonProperty("make_instrumental") boolean makeInstrumental | ||||||
|     ) { |     ) { | ||||||
| @ -136,12 +136,12 @@ public class SunoApi { | |||||||
|             this(prompt, null, null, null, false, false); |             this(prompt, null, null, null, false, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public MusicGenerateRequest(String prompt, String mv, boolean makeInstrumental) { |         public MusicGenerateRequest(String prompt, String model, boolean makeInstrumental) { | ||||||
|             this(prompt, null, null, mv, false, makeInstrumental); |             this(prompt, null, null, model, false, makeInstrumental); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         public MusicGenerateRequest(String prompt, String mv, String tags, String title) { |         public MusicGenerateRequest(String prompt, String model, String tags, String title) { | ||||||
|             this(prompt, tags, title, mv, false, false); |             this(prompt, tags, title, model, false, false); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|     } |     } | ||||||
| @ -162,6 +162,7 @@ public class SunoApi { | |||||||
|      * @param prompt               生成音乐音频的提示 |      * @param prompt               生成音乐音频的提示 | ||||||
|      * @param type                 操作类型 |      * @param type                 操作类型 | ||||||
|      * @param tags                 音乐类型标签 |      * @param tags                 音乐类型标签 | ||||||
|  |      * @param duration             音乐时长 | ||||||
|      */ |      */ | ||||||
|     public record MusicData( |     public record MusicData( | ||||||
|             String id, |             String id, | ||||||
| @ -176,7 +177,8 @@ public class SunoApi { | |||||||
|             @JsonProperty("gpt_description_prompt") String gptDescriptionPrompt, |             @JsonProperty("gpt_description_prompt") String gptDescriptionPrompt, | ||||||
|             String prompt, |             String prompt, | ||||||
|             String type, |             String type, | ||||||
|             String tags |             String tags, | ||||||
|  |             Double duration | ||||||
|     ) { |     ) { | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -201,8 +201,8 @@ yudao.ai: | |||||||
|     notify-url: http://java.nat300.top/admin-api/ai/image/midjourney/notify |     notify-url: http://java.nat300.top/admin-api/ai/image/midjourney/notify | ||||||
|   suno: |   suno: | ||||||
|     enable: true |     enable: true | ||||||
| #    base-url: https://suno-om0w1cy6e-status2xxs-projects.vercel.app |     base-url: https://suno-55ishh05u-status2xxs-projects.vercel.app | ||||||
|     base-url: http://127.0.0.1:3001 | #    base-url: http://127.0.0.1:3001 | ||||||
|  |  | ||||||
| --- #################### 芋道相关配置 #################### | --- #################### 芋道相关配置 #################### | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 芋道源码
					芋道源码