mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 18:49:06 +08:00 
			
		
		
		
	【功能新增】AI:音乐管理 50%
This commit is contained in:
		| @ -29,13 +29,16 @@ public interface ErrorCodeConstants { | |||||||
|  |  | ||||||
|     // ========== API 聊天消息 1-040-004-000 ========== |     // ========== API 聊天消息 1-040-004-000 ========== | ||||||
|  |  | ||||||
|     ErrorCode AI_CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_040_004_000, "消息不存在!"); |     ErrorCode CHAT_MESSAGE_NOT_EXIST = new ErrorCode(1_040_004_000, "消息不存在!"); | ||||||
|     ErrorCode AI_CHAT_STREAM_ERROR = new ErrorCode(1_040_004_001, "Stream 对话异常!"); |     ErrorCode CHAT_STREAM_ERROR = new ErrorCode(1_040_004_001, "Stream 对话异常!"); | ||||||
|  |  | ||||||
|     // ========== API 绘画 1-040-005-000 ========== |     // ========== API 绘画 1-040-005-000 ========== | ||||||
|  |  | ||||||
|     ErrorCode AI_IMAGE_NOT_EXISTS = new ErrorCode(1_022_005_000, "图片不存在!"); |     ErrorCode IMAGE_NOT_EXISTS = new ErrorCode(1_022_005_000, "图片不存在!"); | ||||||
|     ErrorCode AI_IMAGE_MIDJOURNEY_SUBMIT_FAIL = new ErrorCode(1_022_005_001, "Midjourney 提交失败!原因:{}"); |     ErrorCode IMAGE_MIDJOURNEY_SUBMIT_FAIL = new ErrorCode(1_022_005_001, "Midjourney 提交失败!原因:{}"); | ||||||
|     ErrorCode AI_IMAGE_CUSTOM_ID_NOT_EXISTS = new ErrorCode(1_022_005_002, "Midjourney 按钮 customId 不存在! {}"); |     ErrorCode IMAGE_CUSTOM_ID_NOT_EXISTS = new ErrorCode(1_022_005_002, "Midjourney 按钮 customId 不存在! {}"); | ||||||
|  |  | ||||||
|  |     // ========== API 音乐 1-040-006-000 ========== | ||||||
|  |     ErrorCode MUSIC_NOT_EXISTS = new ErrorCode(1_022_006_000, "音乐不存在!"); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,8 +1,11 @@ | |||||||
| package cn.iocoder.yudao.module.ai.enums.music; | package cn.iocoder.yudao.module.ai.enums.music; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
|  |  | ||||||
|  | import java.util.Arrays; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * AI 音乐状态的枚举 |  * AI 音乐状态的枚举 | ||||||
|  * |  * | ||||||
| @ -10,7 +13,7 @@ import lombok.Getter; | |||||||
|  */ |  */ | ||||||
| @AllArgsConstructor | @AllArgsConstructor | ||||||
| @Getter | @Getter | ||||||
| public enum AiMusicGenerateModeEnum { | public enum AiMusicGenerateModeEnum implements IntArrayValuable { | ||||||
|  |  | ||||||
|     LYRIC(1, "歌词模式"), |     LYRIC(1, "歌词模式"), | ||||||
|     DESCRIPTION(2, "描述模式"); |     DESCRIPTION(2, "描述模式"); | ||||||
| @ -24,4 +27,11 @@ public enum AiMusicGenerateModeEnum { | |||||||
|      */ |      */ | ||||||
|     private final String name; |     private final String name; | ||||||
|  |  | ||||||
|  |     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AiMusicGenerateModeEnum::getMode).toArray(); | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public int[] array() { | ||||||
|  |         return ARRAYS; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,8 +1,11 @@ | |||||||
| package cn.iocoder.yudao.module.ai.enums.music; | package cn.iocoder.yudao.module.ai.enums.music; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.core.IntArrayValuable; | ||||||
| import lombok.AllArgsConstructor; | import lombok.AllArgsConstructor; | ||||||
| import lombok.Getter; | import lombok.Getter; | ||||||
|  |  | ||||||
|  | import java.util.Arrays; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * AI 音乐状态的枚举 |  * AI 音乐状态的枚举 | ||||||
|  * |  * | ||||||
| @ -10,7 +13,7 @@ import lombok.Getter; | |||||||
|  */ |  */ | ||||||
| @AllArgsConstructor | @AllArgsConstructor | ||||||
| @Getter | @Getter | ||||||
| public enum AiMusicStatusEnum { | public enum AiMusicStatusEnum implements IntArrayValuable { | ||||||
|  |  | ||||||
|     IN_PROGRESS(10, "进行中"), |     IN_PROGRESS(10, "进行中"), | ||||||
|     SUCCESS(20, "已完成"); |     SUCCESS(20, "已完成"); | ||||||
| @ -25,4 +28,11 @@ public enum AiMusicStatusEnum { | |||||||
|      */ |      */ | ||||||
|     private final String name; |     private final String name; | ||||||
|  |  | ||||||
|  |     public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(AiMusicStatusEnum::getStatus).toArray(); | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public int[] array() { | ||||||
|  |         return ARRAYS; | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,6 +1,5 @@ | |||||||
| package cn.iocoder.yudao.module.ai.controller.admin.image; | package cn.iocoder.yudao.module.ai.controller.admin.image; | ||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; |  | ||||||
| import cn.hutool.core.util.ObjUtil; | import cn.hutool.core.util.ObjUtil; | ||||||
| import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | import cn.iocoder.yudao.framework.ai.core.model.midjourney.api.MidjourneyApi; | ||||||
| import cn.iocoder.yudao.framework.common.pojo.CommonResult; | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||||||
| @ -26,9 +25,7 @@ import org.springframework.security.access.prepost.PreAuthorize; | |||||||
| import org.springframework.validation.annotation.Validated; | import org.springframework.validation.annotation.Validated; | ||||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||||
|  |  | ||||||
| import java.util.Collections; |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Objects; |  | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||||
| import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; | ||||||
| @ -42,15 +39,16 @@ public class AiImageController { | |||||||
|     @Resource |     @Resource | ||||||
|     private AiImageService imageService; |     private AiImageService imageService; | ||||||
|  |  | ||||||
|     @Operation(summary = "获取【我的】绘图分页") |  | ||||||
|     @GetMapping("/my-page") |     @GetMapping("/my-page") | ||||||
|  |     @Operation(summary = "获取【我的】绘图分页") | ||||||
|     public CommonResult<PageResult<AiImageRespVO>> getImagePageMy(@Validated PageParam pageReqVO) { |     public CommonResult<PageResult<AiImageRespVO>> getImagePageMy(@Validated PageParam pageReqVO) { | ||||||
|         PageResult<AiImageDO> pageResult = imageService.getImagePageMy(getLoginUserId(), pageReqVO); |         PageResult<AiImageDO> pageResult = imageService.getImagePageMy(getLoginUserId(), pageReqVO); | ||||||
|         return success(BeanUtils.toBean(pageResult, AiImageRespVO.class)); |         return success(BeanUtils.toBean(pageResult, AiImageRespVO.class)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Operation(summary = "获取【我的】绘图记录") |  | ||||||
|     @GetMapping("/get-my") |     @GetMapping("/get-my") | ||||||
|  |     @Operation(summary = "获取【我的】绘图记录") | ||||||
|  |     @Parameter(name = "id", required = true, description = "绘画编号", example = "1024") | ||||||
|     public CommonResult<AiImageRespVO> getImageMy(@RequestParam("id") Long id) { |     public CommonResult<AiImageRespVO> getImageMy(@RequestParam("id") Long id) { | ||||||
|         AiImageDO image = imageService.getImage(id); |         AiImageDO image = imageService.getImage(id); | ||||||
|         if (image == null || ObjUtil.notEqual(getLoginUserId(), image.getUserId())) { |         if (image == null || ObjUtil.notEqual(getLoginUserId(), image.getUserId())) { | ||||||
| @ -59,17 +57,13 @@ public class AiImageController { | |||||||
|         return success(BeanUtils.toBean(image, AiImageRespVO.class)); |         return success(BeanUtils.toBean(image, AiImageRespVO.class)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Operation(summary = "获取【我的】绘图记录 - ids") |  | ||||||
|     @GetMapping("/get-my-ids") |     @GetMapping("/get-my-ids") | ||||||
|  |     @Operation(summary = "获取【我的】绘图记录列表") | ||||||
|  |     @Parameter(name = "ids", required = true, description = "绘画编号数组", example = "1024,2048") | ||||||
|     public CommonResult<List<AiImageRespVO>> getImageMyIds(@RequestParam("ids") List<Long> ids) { |     public CommonResult<List<AiImageRespVO>> getImageMyIds(@RequestParam("ids") List<Long> ids) { | ||||||
|         List<AiImageDO> imageList = imageService.getImageByIds(ids); |         List<AiImageDO> imageList = imageService.getImageByIds(ids); | ||||||
|         if (CollUtil.isEmpty(imageList)) { |         imageList.removeIf(item -> !ObjUtil.equal(getLoginUserId(), item.getUserId())); | ||||||
|             return success(Collections.emptyList()); |         return success(BeanUtils.toBean(imageList, AiImageRespVO.class)); | ||||||
|         } |  | ||||||
|         List<AiImageDO> userImageList = imageList.stream() |  | ||||||
|                 .map(item -> ObjUtil.equal(getLoginUserId(), item.getUserId()) ? item : null) |  | ||||||
|                 .filter(Objects::nonNull).toList(); |  | ||||||
|         return success(BeanUtils.toBean(userImageList, AiImageRespVO.class)); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     @Operation(summary = "生成图片") |     @Operation(summary = "生成图片") | ||||||
|  | |||||||
| @ -20,7 +20,7 @@ public class AiImagePageReqVO extends PageParam { | |||||||
|     @Schema(description = "用户编号", example = "28987") |     @Schema(description = "用户编号", example = "28987") | ||||||
|     private Long userId; |     private Long userId; | ||||||
|  |  | ||||||
|     @Schema(description = "平台") |     @Schema(description = "平台", example = "OpenAI") | ||||||
|     private String platform; |     private String platform; | ||||||
|  |  | ||||||
|     @Schema(description = "绘画状态", example = "1") |     @Schema(description = "绘画状态", example = "1") | ||||||
|  | |||||||
| @ -1,13 +0,0 @@ | |||||||
| ### 生成音乐:Suno + |  | ||||||
| POST {{baseUrl}}/ai/music/generate |  | ||||||
| Content-Type: application/json |  | ||||||
| Authorization: {{token}} |  | ||||||
|  |  | ||||||
| { |  | ||||||
|   "platform": "Suno", |  | ||||||
|   "generateMode": 1, |  | ||||||
|   "prompt": "来一首快乐的歌曲", |  | ||||||
|   "modelVersion": "chirp-v3.5", |  | ||||||
|   "tags": ["Happy"], |  | ||||||
|   "title": "Happy Song" |  | ||||||
| } |  | ||||||
| @ -0,0 +1,26 @@ | |||||||
|  | ### 生成音乐:Suno + 歌词模式 | ||||||
|  | POST {{baseUrl}}/ai/music/generate | ||||||
|  | Content-Type: application/json | ||||||
|  | Authorization: {{token}} | ||||||
|  |  | ||||||
|  | { | ||||||
|  |   "platform": "Suno", | ||||||
|  |   "generateMode": 1, | ||||||
|  |   "prompt": "来一首快乐的歌曲", | ||||||
|  |   "modelVersion": "chirp-v3.5", | ||||||
|  |   "tags": ["Happy"], | ||||||
|  |   "title": "Happy Song" | ||||||
|  | } | ||||||
|  |  | ||||||
|  | ### 生成音乐:Suno + 描述模式 | ||||||
|  | POST {{baseUrl}}/ai/music/generate | ||||||
|  | Content-Type: application/json | ||||||
|  | Authorization: {{token}} | ||||||
|  |  | ||||||
|  | { | ||||||
|  |   "platform": "Suno", | ||||||
|  |   "generateMode": 2, | ||||||
|  |   "prompt": "来一首快乐的歌曲", | ||||||
|  |   "makeInstrumental": false, | ||||||
|  |   "title": "Happy Song" | ||||||
|  | } | ||||||
| @ -1,16 +1,21 @@ | |||||||
| package cn.iocoder.yudao.module.ai.controller.admin.music; | package cn.iocoder.yudao.module.ai.controller.admin.music; | ||||||
|  |  | ||||||
| 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.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.AiSunoGenerateReqVO; | ||||||
|  | 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; | ||||||
|  | import io.swagger.v3.oas.annotations.Parameter; | ||||||
| import io.swagger.v3.oas.annotations.tags.Tag; | import io.swagger.v3.oas.annotations.tags.Tag; | ||||||
| import jakarta.annotation.Resource; | import jakarta.annotation.Resource; | ||||||
| import jakarta.validation.Valid; | import jakarta.validation.Valid; | ||||||
| import org.springframework.web.bind.annotation.PostMapping; | import org.springframework.security.access.prepost.PreAuthorize; | ||||||
| import org.springframework.web.bind.annotation.RequestBody; | import org.springframework.web.bind.annotation.*; | ||||||
| import org.springframework.web.bind.annotation.RequestMapping; |  | ||||||
| import org.springframework.web.bind.annotation.RestController; |  | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| @ -31,4 +36,31 @@ public class AiMusicController { | |||||||
|         return success(musicService.generateMusic(getLoginUserId(), reqVO)); |         return success(musicService.generateMusic(getLoginUserId(), reqVO)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // ================ 绘图管理 ================ | ||||||
|  |  | ||||||
|  |     @GetMapping("/page") | ||||||
|  |     @Operation(summary = "获得音乐分页") | ||||||
|  |     @PreAuthorize("@ss.hasPermission('ai:music:query')") | ||||||
|  |     public CommonResult<PageResult<AiMusicRespVO>> getMusicPage(@Valid AiMusicPageReqVO pageReqVO) { | ||||||
|  |         PageResult<AiMusicDO> pageResult = musicService.getMusicPage(pageReqVO); | ||||||
|  |         return success(BeanUtils.toBean(pageResult, AiMusicRespVO.class)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @DeleteMapping("/delete") | ||||||
|  |     @Operation(summary = "删除音乐") | ||||||
|  |     @Parameter(name = "id", description = "编号", required = true) | ||||||
|  |     @PreAuthorize("@ss.hasPermission('ai:music:delete')") | ||||||
|  |     public CommonResult<Boolean> deleteMusic(@RequestParam("id") Long id) { | ||||||
|  |         musicService.deleteMusic(id); | ||||||
|  |         return success(true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @PutMapping("/update") | ||||||
|  |     @Operation(summary = "更新音乐发布状态") | ||||||
|  |     @PreAuthorize("@ss.hasPermission('ai:music:update')") | ||||||
|  |     public CommonResult<Boolean> updateMusicPublicStatus(@Valid @RequestBody AiMusicUpdatePublicStatusReqVO updateReqVO) { | ||||||
|  |         musicService.updateMusicPublicStatus(updateReqVO); | ||||||
|  |         return success(true); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -0,0 +1,44 @@ | |||||||
|  | package cn.iocoder.yudao.module.ai.controller.admin.music.vo; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.pojo.PageParam; | ||||||
|  | import cn.iocoder.yudao.framework.common.validation.InEnum; | ||||||
|  | import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; | ||||||
|  | import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import lombok.Data; | ||||||
|  | import lombok.EqualsAndHashCode; | ||||||
|  | import lombok.ToString; | ||||||
|  | import org.springframework.format.annotation.DateTimeFormat; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  |  | ||||||
|  | import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | ||||||
|  |  | ||||||
|  | @Schema(description = "管理后台 - AI 音乐分页 Request VO") | ||||||
|  | @Data | ||||||
|  | @EqualsAndHashCode(callSuper = true) | ||||||
|  | @ToString(callSuper = true) | ||||||
|  | public class AiMusicPageReqVO extends PageParam { | ||||||
|  |  | ||||||
|  |     @Schema(description = "用户编号", example = "12212") | ||||||
|  |     private Long userId; | ||||||
|  |  | ||||||
|  |     @Schema(description = "音乐名称", example = "夜空中最亮的星") | ||||||
|  |     private String title; | ||||||
|  |  | ||||||
|  |     @Schema(description = "音乐状态", example = "20") | ||||||
|  |     @InEnum(AiMusicStatusEnum.class) | ||||||
|  |     private Integer status; | ||||||
|  |  | ||||||
|  |     @Schema(description = "生成模式", example = "1") | ||||||
|  |     @InEnum(AiMusicGenerateModeEnum.class) | ||||||
|  |     private Integer generateMode; | ||||||
|  |  | ||||||
|  |     @Schema(description = "是否发布", example = "true") | ||||||
|  |     private Boolean publicStatus; | ||||||
|  |  | ||||||
|  |     @Schema(description = "创建时间") | ||||||
|  |     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | ||||||
|  |     private LocalDateTime[] createTime; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -0,0 +1,67 @@ | |||||||
|  | package cn.iocoder.yudao.module.ai.controller.admin.music.vo; | ||||||
|  |  | ||||||
|  | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
|  | import lombok.Data; | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime; | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | @Schema(description = "管理后台 - AI 音乐 Response VO") | ||||||
|  | @Data | ||||||
|  | public class AiMusicRespVO { | ||||||
|  |  | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "24790") | ||||||
|  |     private Long id; | ||||||
|  |  | ||||||
|  |     @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12212") | ||||||
|  |     private Long userId; | ||||||
|  |  | ||||||
|  |     @Schema(description = "音乐名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "夜空中最亮的星") | ||||||
|  |     private String title; | ||||||
|  |  | ||||||
|  |     @Schema(description = "歌词", example = "oh~卖糕的") | ||||||
|  |     private String lyric; | ||||||
|  |  | ||||||
|  |     @Schema(description = "图片地址", example = "https://www.iocoder.cn") | ||||||
|  |     private String imageUrl; | ||||||
|  |  | ||||||
|  |     @Schema(description = "音频地址", example = "https://www.iocoder.cn") | ||||||
|  |     private String audioUrl; | ||||||
|  |  | ||||||
|  |     @Schema(description = "视频地址", example = "https://www.iocoder.cn") | ||||||
|  |     private String videoUrl; | ||||||
|  |  | ||||||
|  |     @Schema(description = "音乐状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") | ||||||
|  |     private Integer status; | ||||||
|  |  | ||||||
|  |     @Schema(description = "描述词", example = "一首轻快的歌曲") | ||||||
|  |     private String gptDescriptionPrompt; | ||||||
|  |  | ||||||
|  |     @Schema(description = "提示词", example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。") | ||||||
|  |     private String prompt; | ||||||
|  |  | ||||||
|  |     @Schema(description = "模型平台", requiredMode = Schema.RequiredMode.REQUIRED, example = "Suno") | ||||||
|  |     private String platform; | ||||||
|  |  | ||||||
|  |     @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5") | ||||||
|  |     private String model; | ||||||
|  |  | ||||||
|  |     @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | ||||||
|  |     private Integer generateMode; | ||||||
|  |  | ||||||
|  |     @Schema(description = "音乐风格标签") | ||||||
|  |     private List<String> tags; | ||||||
|  |  | ||||||
|  |     @Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | ||||||
|  |     private Boolean publicStatus; | ||||||
|  |  | ||||||
|  |     @Schema(description = "任务编号", example = "11369") | ||||||
|  |     private String taskId; | ||||||
|  |  | ||||||
|  |     @Schema(description = "错误信息") | ||||||
|  |     private String errorMessage; | ||||||
|  |  | ||||||
|  |     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | ||||||
|  |     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 AiMusicUpdatePublicStatusReqVO { | ||||||
|  |  | ||||||
|  |     @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583") | ||||||
|  |     private Long id; | ||||||
|  |  | ||||||
|  |     @Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") | ||||||
|  |     @NotNull(message = "是否发布不能为空") | ||||||
|  |     private Boolean publicStatus; | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.controller.admin.music.vo; | |||||||
|  |  | ||||||
| import io.swagger.v3.oas.annotations.media.Schema; | import io.swagger.v3.oas.annotations.media.Schema; | ||||||
| import jakarta.validation.constraints.NotBlank; | import jakarta.validation.constraints.NotBlank; | ||||||
|  | import jakarta.validation.constraints.NotEmpty; | ||||||
| import jakarta.validation.constraints.NotNull; | import jakarta.validation.constraints.NotNull; | ||||||
| import lombok.Data; | import lombok.Data; | ||||||
|  |  | ||||||
| @ -15,6 +16,10 @@ public class AiSunoGenerateReqVO { | |||||||
|     @NotBlank(message = "平台不能为空") |     @NotBlank(message = "平台不能为空") | ||||||
|     private String platform; // 参见 AiPlatformEnum 枚举 |     private String platform; // 参见 AiPlatformEnum 枚举 | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 1. 描述模式:描述词 + 是否纯音乐 + 模型 TODO @xin:目前貌似描述词没弄对?看着不是 prompt 字段(也可能我弄错了)。可以微信再沟通下哈 | ||||||
|  |      * 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型 TODO @xin:目前这块少传递了标题; | ||||||
|  |      */ | ||||||
|     @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |     @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | ||||||
|     @NotNull(message = "生成模式不能为空") |     @NotNull(message = "生成模式不能为空") | ||||||
|     private Integer generateMode; // 参见 AiMusicGenerateModeEnum 枚举 |     private Integer generateMode; // 参见 AiMusicGenerateModeEnum 枚举 | ||||||
| @ -26,7 +31,9 @@ public class AiSunoGenerateReqVO { | |||||||
|     @Schema(description = "是否纯音乐", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "true") |     @Schema(description = "是否纯音乐", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "true") | ||||||
|     private Boolean makeInstrumental; |     private Boolean makeInstrumental; | ||||||
|  |  | ||||||
|     @Schema(description = "模型版本", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "chirp-v3.5") |     // TODO @xin:看了下这个字段,发现最终还是 model 合适点;因为它其实是模型 | ||||||
|  |     @Schema(description = "模型版本", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5") | ||||||
|  |     @NotEmpty(message = "模型不能为空") | ||||||
|     private String modelVersion; // 参见 AiModelEnum 枚举 |     private String modelVersion; // 参见 AiModelEnum 枚举 | ||||||
|  |  | ||||||
|     @Schema(description = "音乐风格", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "[\"pop\",\"jazz\",\"punk\"]") |     @Schema(description = "音乐风格", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "[\"pop\",\"jazz\",\"punk\"]") | ||||||
|  | |||||||
| @ -98,6 +98,11 @@ public class AiMusicDO extends BaseDO { | |||||||
|     @TableField(typeHandler = JacksonTypeHandler.class) |     @TableField(typeHandler = JacksonTypeHandler.class) | ||||||
|     private List<String> tags; |     private List<String> tags; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 是否公开 | ||||||
|  |      */ | ||||||
|  |     private Boolean publicStatus; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 任务编号 |      * 任务编号 | ||||||
|      */ |      */ | ||||||
|  | |||||||
| @ -1,6 +1,9 @@ | |||||||
| package cn.iocoder.yudao.module.ai.dal.mysql.music; | package cn.iocoder.yudao.module.ai.dal.mysql.music; | ||||||
|  |  | ||||||
|  | import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||||||
| import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; | ||||||
|  | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; | ||||||
|  | import cn.iocoder.yudao.module.ai.controller.admin.music.vo.AiMusicPageReqVO; | ||||||
| import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | ||||||
| import org.apache.ibatis.annotations.Mapper; | import org.apache.ibatis.annotations.Mapper; | ||||||
|  |  | ||||||
| @ -18,4 +21,15 @@ public interface AiMusicMapper extends BaseMapperX<AiMusicDO> { | |||||||
|         return selectList(AiMusicDO::getStatus, status); |         return selectList(AiMusicDO::getStatus, status); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     default PageResult<AiMusicDO> selectPage(AiMusicPageReqVO reqVO) { | ||||||
|  |         return selectPage(reqVO, new LambdaQueryWrapperX<AiMusicDO>() | ||||||
|  |                 .eqIfPresent(AiMusicDO::getUserId, reqVO.getUserId()) | ||||||
|  |                 .eqIfPresent(AiMusicDO::getTitle, reqVO.getTitle()) | ||||||
|  |                 .eqIfPresent(AiMusicDO::getStatus, reqVO.getStatus()) | ||||||
|  |                 .eqIfPresent(AiMusicDO::getGenerateMode, reqVO.getGenerateMode()) | ||||||
|  |                 .betweenIfPresent(AiMusicDO::getCreateTime, reqVO.getCreateTime()) | ||||||
|  |                 .eqIfPresent(AiMusicDO::getPublicStatus, reqVO.getPublicStatus()) | ||||||
|  |                 .orderByDesc(AiMusicDO::getId)); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU | |||||||
| import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; | ||||||
| import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; | ||||||
| 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.module.ai.enums.ErrorCodeConstants.AI_CHAT_MESSAGE_NOT_EXIST; | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_MESSAGE_NOT_EXIST; | ||||||
| import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -150,7 +150,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | |||||||
|             log.error("[sendChatMessageStream][userId({}) sendReqVO({}) 发生异常]", userId, sendReqVO, throwable); |             log.error("[sendChatMessageStream][userId({}) sendReqVO({}) 发生异常]", userId, sendReqVO, throwable); | ||||||
|             chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(throwable.getMessage())); |             chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(throwable.getMessage())); | ||||||
|         }).onErrorResume(error -> { |         }).onErrorResume(error -> { | ||||||
|             return Flux.just(error(ErrorCodeConstants.AI_CHAT_STREAM_ERROR)); |             return Flux.just(error(ErrorCodeConstants.CHAT_STREAM_ERROR)); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -257,7 +257,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | |||||||
|         // 1. 校验消息存在 |         // 1. 校验消息存在 | ||||||
|         AiChatMessageDO message = chatMessageMapper.selectById(id); |         AiChatMessageDO message = chatMessageMapper.selectById(id); | ||||||
|         if (message == null || ObjUtil.notEqual(message.getUserId(), userId)) { |         if (message == null || ObjUtil.notEqual(message.getUserId(), userId)) { | ||||||
|             throw exception(AI_CHAT_MESSAGE_NOT_EXIST); |             throw exception(CHAT_MESSAGE_NOT_EXIST); | ||||||
|         } |         } | ||||||
|         // 2. 执行删除 |         // 2. 执行删除 | ||||||
|         chatMessageMapper.deleteById(id); |         chatMessageMapper.deleteById(id); | ||||||
| @ -268,7 +268,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | |||||||
|         // 1. 校验消息存在 |         // 1. 校验消息存在 | ||||||
|         List<AiChatMessageDO> messages = chatMessageMapper.selectListByConversationId(conversationId); |         List<AiChatMessageDO> messages = chatMessageMapper.selectListByConversationId(conversationId); | ||||||
|         if (CollUtil.isEmpty(messages) || ObjUtil.notEqual(messages.get(0).getUserId(), userId)) { |         if (CollUtil.isEmpty(messages) || ObjUtil.notEqual(messages.get(0).getUserId(), userId)) { | ||||||
|             throw exception(AI_CHAT_MESSAGE_NOT_EXIST); |             throw exception(CHAT_MESSAGE_NOT_EXIST); | ||||||
|         } |         } | ||||||
|         // 2. 执行删除 |         // 2. 执行删除 | ||||||
|         chatMessageMapper.deleteBatchIds(convertList(messages, AiChatMessageDO::getId)); |         chatMessageMapper.deleteBatchIds(convertList(messages, AiChatMessageDO::getId)); | ||||||
| @ -279,7 +279,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { | |||||||
|         // 1. 校验消息存在 |         // 1. 校验消息存在 | ||||||
|         AiChatMessageDO message = chatMessageMapper.selectById(id); |         AiChatMessageDO message = chatMessageMapper.selectById(id); | ||||||
|         if (message == null) { |         if (message == null) { | ||||||
|             throw exception(AI_CHAT_MESSAGE_NOT_EXIST); |             throw exception(CHAT_MESSAGE_NOT_EXIST); | ||||||
|         } |         } | ||||||
|         // 2. 执行删除 |         // 2. 执行删除 | ||||||
|         chatMessageMapper.deleteById(id); |         chatMessageMapper.deleteById(id); | ||||||
|  | |||||||
| @ -35,6 +35,7 @@ import org.springframework.scheduling.annotation.Async; | |||||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
|  |  | ||||||
|  | import java.util.Collections; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.Map; | import java.util.Map; | ||||||
|  |  | ||||||
| @ -76,6 +77,9 @@ public class AiImageServiceImpl implements AiImageService { | |||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<AiImageDO> getImageByIds(List<Long> ids) { |     public List<AiImageDO> getImageByIds(List<Long> ids) { | ||||||
|  |         if (CollUtil.isEmpty(ids)) { | ||||||
|  |             return Collections.emptyList(); | ||||||
|  |         } | ||||||
|         return imageMapper.selectBatchIds(ids); |         return imageMapper.selectBatchIds(ids); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -135,7 +139,7 @@ public class AiImageServiceImpl implements AiImageService { | |||||||
|         // 1. 校验是否存在 |         // 1. 校验是否存在 | ||||||
|         AiImageDO image = validateImageExists(id); |         AiImageDO image = validateImageExists(id); | ||||||
|         if (ObjUtil.notEqual(image.getUserId(), userId)) { |         if (ObjUtil.notEqual(image.getUserId(), userId)) { | ||||||
|             throw exception(AI_IMAGE_NOT_EXISTS); |             throw exception(IMAGE_NOT_EXISTS); | ||||||
|         } |         } | ||||||
|         // 2. 删除记录 |         // 2. 删除记录 | ||||||
|         imageMapper.deleteById(id); |         imageMapper.deleteById(id); | ||||||
| @ -165,7 +169,7 @@ public class AiImageServiceImpl implements AiImageService { | |||||||
|     private AiImageDO validateImageExists(Long id) { |     private AiImageDO validateImageExists(Long id) { | ||||||
|         AiImageDO image = imageMapper.selectById(id); |         AiImageDO image = imageMapper.selectById(id); | ||||||
|         if (image == null) { |         if (image == null) { | ||||||
|             throw exception(AI_IMAGE_NOT_EXISTS); |             throw exception(IMAGE_NOT_EXISTS); | ||||||
|         } |         } | ||||||
|         return image; |         return image; | ||||||
|     } |     } | ||||||
| @ -191,7 +195,7 @@ public class AiImageServiceImpl implements AiImageService { | |||||||
|         if (!MidjourneyApi.SubmitCodeEnum.SUCCESS_CODES.contains(imagineResponse.code())) { |         if (!MidjourneyApi.SubmitCodeEnum.SUCCESS_CODES.contains(imagineResponse.code())) { | ||||||
|             String description = imagineResponse.description().contains("quota_not_enough") ? |             String description = imagineResponse.description().contains("quota_not_enough") ? | ||||||
|                     "账户余额不足" : imagineResponse.description(); |                     "账户余额不足" : imagineResponse.description(); | ||||||
|             throw exception(AI_IMAGE_MIDJOURNEY_SUBMIT_FAIL, description); |             throw exception(IMAGE_MIDJOURNEY_SUBMIT_FAIL, description); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 4. 情况二【成功】:更新 taskId 和参数 |         // 4. 情况二【成功】:更新 taskId 和参数 | ||||||
| @ -271,13 +275,13 @@ public class AiImageServiceImpl implements AiImageService { | |||||||
|         // 1.1 检查 image |         // 1.1 检查 image | ||||||
|         AiImageDO image = validateImageExists(reqVO.getId()); |         AiImageDO image = validateImageExists(reqVO.getId()); | ||||||
|         if (ObjUtil.notEqual(userId, image.getUserId())) { |         if (ObjUtil.notEqual(userId, image.getUserId())) { | ||||||
|             throw exception(AI_IMAGE_NOT_EXISTS); |             throw exception(IMAGE_NOT_EXISTS); | ||||||
|         } |         } | ||||||
|         // 1.2 检查 customId |         // 1.2 检查 customId | ||||||
|         MidjourneyApi.Button button = CollUtil.findOne(image.getButtons(), |         MidjourneyApi.Button button = CollUtil.findOne(image.getButtons(), | ||||||
|                 buttonX -> buttonX.customId().equals(reqVO.getCustomId())); |                 buttonX -> buttonX.customId().equals(reqVO.getCustomId())); | ||||||
|         if (button == null) { |         if (button == null) { | ||||||
|             throw exception(AI_IMAGE_CUSTOM_ID_NOT_EXISTS); |             throw exception(IMAGE_CUSTOM_ID_NOT_EXISTS); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 2. 调用 Midjourney Proxy 提交任务 |         // 2. 调用 Midjourney Proxy 提交任务 | ||||||
| @ -286,7 +290,7 @@ public class AiImageServiceImpl implements AiImageService { | |||||||
|         if (!MidjourneyApi.SubmitCodeEnum.SUCCESS_CODES.contains(actionResponse.code())) { |         if (!MidjourneyApi.SubmitCodeEnum.SUCCESS_CODES.contains(actionResponse.code())) { | ||||||
|             String description = actionResponse.description().contains("quota_not_enough") ? |             String description = actionResponse.description().contains("quota_not_enough") ? | ||||||
|                     "账户余额不足" : actionResponse.description(); |                     "账户余额不足" : actionResponse.description(); | ||||||
|             throw exception(AI_IMAGE_MIDJOURNEY_SUBMIT_FAIL, description); |             throw exception(IMAGE_MIDJOURNEY_SUBMIT_FAIL, description); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 3. 新增 image 记录 |         // 3. 新增 image 记录 | ||||||
|  | |||||||
| @ -1,6 +1,11 @@ | |||||||
| 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.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.AiSunoGenerateReqVO; | ||||||
|  | import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; | ||||||
|  | import jakarta.validation.Valid; | ||||||
|  |  | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| @ -27,4 +32,26 @@ public interface AiMusicService { | |||||||
|      */ |      */ | ||||||
|     Integer syncMusic(); |     Integer syncMusic(); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 更新音乐发布状态 | ||||||
|  |      * | ||||||
|  |      * @param updateReqVO 更新信息 | ||||||
|  |      */ | ||||||
|  |     void updateMusicPublicStatus(@Valid AiMusicUpdatePublicStatusReqVO updateReqVO); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 删除AI 音乐 | ||||||
|  |      * | ||||||
|  |      * @param id 编号 | ||||||
|  |      */ | ||||||
|  |     void deleteMusic(Long id); | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获得音乐分页 | ||||||
|  |      * | ||||||
|  |      * @param pageReqVO 分页查询 | ||||||
|  |      * @return 音乐分页 | ||||||
|  |      */ | ||||||
|  |     PageResult<AiMusicDO> getMusicPage(AiMusicPageReqVO pageReqVO); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,6 +4,9 @@ import cn.hutool.core.collection.CollUtil; | |||||||
| import cn.hutool.core.text.StrPool; | import cn.hutool.core.text.StrPool; | ||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
| 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.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.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; | ||||||
| @ -15,8 +18,10 @@ import org.springframework.stereotype.Service; | |||||||
|  |  | ||||||
| import java.util.*; | 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.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.MUSIC_NOT_EXISTS; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * AI 音乐 Service 实现类 |  * AI 音乐 Service 实现类 | ||||||
| @ -56,7 +61,7 @@ public class AiMusicServiceImpl implements AiMusicService { | |||||||
|             return Collections.emptyList(); |             return Collections.emptyList(); | ||||||
|         } |         } | ||||||
|         List<AiMusicDO> musicList = buildMusicDOList(musicDataList); |         List<AiMusicDO> musicList = buildMusicDOList(musicDataList); | ||||||
|         musicList.forEach(music -> music.setUserId(userId).setPlatform(music.getPlatform()).setGenerateMode(reqVO.getGenerateMode())); |         musicList.forEach(music -> music.setUserId(userId).setPlatform(reqVO.getPlatform()).setGenerateMode(reqVO.getGenerateMode())); | ||||||
|         musicMapper.insertBatch(musicList); |         musicMapper.insertBatch(musicList); | ||||||
|         return convertList(musicList, AiMusicDO::getId); |         return convertList(musicList, AiMusicDO::getId); | ||||||
|     } |     } | ||||||
| @ -92,12 +97,41 @@ public class AiMusicServiceImpl implements AiMusicService { | |||||||
|      * @return AiMusicDO 集合 |      * @return AiMusicDO 集合 | ||||||
|      */ |      */ | ||||||
|     private static List<AiMusicDO> buildMusicDOList(List<SunoApi.MusicData> musicList) { |     private static List<AiMusicDO> buildMusicDOList(List<SunoApi.MusicData> musicList) { | ||||||
|  |         // TODO @xin:成功的情况下,需要下载到自己的文件服务器。参考图片的处理 | ||||||
|         return convertList(musicList, musicData -> new AiMusicDO() |         return convertList(musicList, musicData -> new AiMusicDO() | ||||||
|                 .setTaskId(musicData.id()).setModel(musicData.modelName()) |                 .setTaskId(musicData.id()).setModel(musicData.modelName()) | ||||||
|                 .setPrompt(musicData.prompt()).setGptDescriptionPrompt(musicData.gptDescriptionPrompt()) |                 .setPrompt(musicData.prompt()).setGptDescriptionPrompt(musicData.gptDescriptionPrompt()) | ||||||
|                 .setAudioUrl(musicData.audioUrl()).setVideoUrl(musicData.videoUrl()).setImageUrl(musicData.imageUrl()) |                 .setAudioUrl(musicData.audioUrl()).setVideoUrl(musicData.videoUrl()).setImageUrl(musicData.imageUrl()) | ||||||
|                 .setTitle(musicData.title()).setLyric(musicData.lyric()).setTags(StrUtil.split(musicData.tags(), StrPool.COMMA)) |                 .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())); |                 .setStatus(Objects.equals("complete", musicData.status()) ? | ||||||
|  |                         AiMusicStatusEnum.SUCCESS.getStatus() : AiMusicStatusEnum.IN_PROGRESS.getStatus())); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void updateMusicPublicStatus(AiMusicUpdatePublicStatusReqVO updateReqVO) { | ||||||
|  |         // 校验存在 | ||||||
|  |         validateMusicExists(updateReqVO.getId()); | ||||||
|  |         // 更新 | ||||||
|  |         musicMapper.updateBatch(new AiMusicDO().setPublicStatus(updateReqVO.getPublicStatus())); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void deleteMusic(Long id) { | ||||||
|  |         // 校验存在 | ||||||
|  |         validateMusicExists(id); | ||||||
|  |         // 删除 | ||||||
|  |         musicMapper.deleteById(id); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private void validateMusicExists(Long id) { | ||||||
|  |         if (musicMapper.selectById(id) == null) { | ||||||
|  |             throw exception(MUSIC_NOT_EXISTS); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public PageResult<AiMusicDO> getMusicPage(AiMusicPageReqVO pageReqVO) { | ||||||
|  |         return musicMapper.selectPage(pageReqVO); | ||||||
|  |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -17,7 +17,8 @@ public class SunoTests { | |||||||
|  |  | ||||||
|     @Before |     @Before | ||||||
|     public void setup() { |     public void setup() { | ||||||
|         String url = "https://suno-om0w1cy6e-status2xxs-projects.vercel.app"; | //        String url = "https://suno-om0w1cy6e-status2xxs-projects.vercel.app"; | ||||||
|  |         String url = "http://127.0.0.1:3001"; | ||||||
|         this.sunoApi = new SunoApi(url); |         this.sunoApi = new SunoApi(url); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -53,5 +54,4 @@ public class SunoTests { | |||||||
|         System.out.println(limitUsageData); |         System.out.println(limitUsageData); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -201,7 +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-om0w1cy6e-status2xxs-projects.vercel.app | ||||||
|  |     base-url: http://127.0.0.1:3001 | ||||||
|  |  | ||||||
| --- #################### 芋道相关配置 #################### | --- #################### 芋道相关配置 #################### | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 YunaiV
					YunaiV