diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.http b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.http index 58524ee83..20df8d132 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.http +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.http @@ -5,9 +5,9 @@ Authorization: {{token}} { "platform": "Suno", - "generateMode": 1, - "prompt": "来一首快乐的歌曲", - "modelVersion": "chirp-v3.5", + "generateMode": 2, + "prompt": "周末啦!", + "model": "chirp-v3.5", "tags": ["Happy"], "title": "Happy Song" } @@ -19,8 +19,8 @@ Authorization: {{token}} { "platform": "Suno", - "generateMode": 2, - "prompt": "来一首快乐的歌曲", - "makeInstrumental": false, - "title": "Happy Song" + "generateMode": 1, + "model": "chirp-v3.5", + "gptDescriptionPrompt": "今天是星球六,结果是个下雨天,希望心情很美丽", + "makeInstrumental": false } \ 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/AiMusicController.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/AiMusicController.java index 2fac7b367..d73a542dc 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 @@ -35,6 +35,16 @@ public class AiMusicController { return success(BeanUtils.toBean(pageResult, AiMusicRespVO.class)); } + @PostMapping("/generate") + @Operation(summary = "音乐生成") + public CommonResult> generateMusic(@RequestBody @Valid AiSunoGenerateReqVO reqVO) { + if (true) { + musicService.syncMusic(); + return null; + } + return success(musicService.generateMusic(getLoginUserId(), reqVO)); + } + @Operation(summary = "删除【我的】音乐记录") @DeleteMapping("/delete-my") @Parameter(name = "id", required = true, description = "音乐编号", example = "1024") @@ -54,6 +64,7 @@ public class AiMusicController { return success(BeanUtils.toBean(music, AiMusicRespVO.class)); } + // TODO @xin:这个搞成 updateMy ,修改【我的】音乐。方便后续支持其它字段;另外,需要校验下,更新的音乐,是不是我的! @PostMapping("/updateTitle-my") @Operation(summary = "修改【我的】音乐 目前只支持修改标题") @Parameter(name = "title", required = true, description = "音乐名称", example = "夜空中最亮的星") @@ -62,12 +73,6 @@ public class AiMusicController { return success(true); } - @PostMapping("/generate") - @Operation(summary = "音乐生成") - public CommonResult> generateMusic(@RequestBody @Valid AiSunoGenerateReqVO reqVO) { - return success(musicService.generateMusic(getLoginUserId(), reqVO)); - } - // ================ 音乐管理 ================ @GetMapping("/page") @@ -87,11 +92,11 @@ public class AiMusicController { return success(true); } - @PutMapping("/update-public-status") - @Operation(summary = "更新音乐发布状态") + @PutMapping("/update") + @Operation(summary = "更新音乐") @PreAuthorize("@ss.hasPermission('ai:music:update')") - public CommonResult updateMusicPublicStatus(@Valid @RequestBody AiMusicUpdatePublicStatusReqVO updateReqVO) { - musicService.updateMusicPublicStatus(updateReqVO); + public CommonResult updateMusic(@Valid @RequestBody AiMusicUpdateReqVO updateReqVO) { + musicService.updateMusic(updateReqVO); return success(true); } 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 8c7db3605..05044a4e7 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 @@ -52,6 +52,9 @@ public class AiMusicRespVO { @Schema(description = "音乐风格标签") private List tags; + @Schema(description = "音乐时长", example = "[\"pop\",\"jazz\",\"punk\"]") + private Double duration; + @Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") private Boolean publicStatus; @@ -61,9 +64,6 @@ 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/AiMusicUpdatePublicStatusReqVO.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdateReqVO.java similarity index 55% rename from yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdatePublicStatusReqVO.java rename to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdateReqVO.java index 30d7afba1..447bc9765 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdatePublicStatusReqVO.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/music/vo/AiMusicUpdateReqVO.java @@ -4,15 +4,15 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import lombok.Data; -@Schema(description = "管理后台 - AI 音乐修改发布状态 Request VO") +@Schema(description = "管理后台 - AI 音乐修改 Request VO") @Data -public class AiMusicUpdatePublicStatusReqVO { +public class AiMusicUpdateReqVO { @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15583") + @NotNull(message = "编号不能为空") private Long id; - @Schema(description = "是否发布", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") - @NotNull(message = "是否发布不能为空") + @Schema(description = "是否发布", example = "true") private Boolean publicStatus; } \ 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 66b40e44a..a0e7a0738 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 @@ -20,11 +20,13 @@ public class AiSunoGenerateReqVO { * 1. 描述模式:描述词 + 是否纯音乐 + 模型 * 2. 歌词模式:歌词 + 音乐风格 + 标题 + 模型 */ - @Schema(description = "生成模式 1.描述模式 2. 歌词模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @Schema(description = "生成模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") @NotNull(message = "生成模式不能为空") private Integer generateMode; // 参见 AiMusicGenerateModeEnum 枚举 - @Schema(description = "歌词模式用:用于生成音乐音频的歌词提示", requiredMode = Schema.RequiredMode.NOT_REQUIRED, + // TODO @xin:方案一:prompt => lyric 歌词;gptDescriptionPrompt => description 描述(db 那字段也改下,避免和 gpt 直接耦合);这样搞完后,会更统一好理解一点 + // TODO @xin:方案二:还是之前的做法,都用 prompt;不过最终 gptDescriptionPrompt 还是存储 description 算描述。可以微信一起讨论下。 + @Schema(description = "用于生成音乐音频的歌词提示", example = """ [Verse] 阳光下奔跑 多么欢快 @@ -37,23 +39,23 @@ public class AiSunoGenerateReqVO { 日子太短暂 别再等待 马上放假了 梦想起飞 """) - private String prompt; + private String prompt; // 歌词模式用 - @Schema(description = "描述模式用:用于生成音乐音频的描述", requiredMode = Schema.RequiredMode.NOT_REQUIRED, + @Schema(description = "用于生成音乐音频的描述", example = "创作一首带有轻松吉他旋律的流行歌曲,[verse] 描述夏日海滩的宁静,[chorus] 节奏加快,表达对自由的向往。") - private String gptDescriptionPrompt; + private String gptDescriptionPrompt; // 描述模式用 - @Schema(description = "是否纯音乐", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "true") + @Schema(description = "是否纯音乐", example = "true") private Boolean makeInstrumental; @Schema(description = "模型", requiredMode = Schema.RequiredMode.REQUIRED, example = "chirp-v3.5") @NotEmpty(message = "模型不能为空") private String model; // 参见 AiModelEnum 枚举 - @Schema(description = "音乐风格", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "[\"pop\",\"jazz\",\"punk\"]") + @Schema(description = "音乐风格", example = "[\"pop\",\"jazz\",\"punk\"]") private List tags; - @Schema(description = "音乐/歌曲名称", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "夜空中最亮的星") + @Schema(description = "音乐/歌曲名称", example = "夜空中最亮的星") 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/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 56fd87704..76a810f82 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 @@ -98,6 +98,11 @@ public class AiMusicDO extends BaseDO { @TableField(typeHandler = JacksonTypeHandler.class) private List tags; + /** + * 音乐时长 + */ + private Double duration; + /** * 是否公开 */ @@ -113,10 +118,4 @@ 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/service/model/AiApiKeyService.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyService.java index 20cda18af..ae0565195 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyService.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyService.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.module.ai.service.model; import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +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.model.vo.apikey.AiApiKeyPageReqVO; import cn.iocoder.yudao.module.ai.controller.admin.model.vo.apikey.AiApiKeySaveReqVO; @@ -91,4 +92,13 @@ public interface AiApiKeyService { */ ImageClient getImageClient(AiPlatformEnum platform); + /** + * 获得 SunoApi 对象 + * + * TODO 可优化点:目前默认获取 Suno 对应的第一个开启的配置用于音乐;后续可以支持配置选择 + * + * @return SunoApi 对象 + */ + SunoApi getSunoApi(); + } \ No newline at end of file diff --git a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyServiceImpl.java b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyServiceImpl.java index 14ea6d43e..f68ba3ae0 100644 --- a/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyServiceImpl.java +++ b/yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiApiKeyServiceImpl.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.ai.service.model; import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; import cn.iocoder.yudao.framework.ai.core.factory.AiClientFactory; +import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -111,4 +112,14 @@ public class AiApiKeyServiceImpl implements AiApiKeyService { return clientFactory.getOrCreateImageClient(platform, apiKey.getApiKey(), apiKey.getUrl()); } + @Override + public SunoApi getSunoApi() { + AiApiKeyDO apiKey = apiKeyMapper.selectFirstByPlatformAndStatus( + AiPlatformEnum.SUNO.getPlatform(), CommonStatusEnum.ENABLE.getStatus()); + if (apiKey == null) { + return null; + } + return clientFactory.getOrCreateSunoApi(apiKey.getApiKey(), apiKey.getUrl()); + } + } \ No newline at end of file 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 af8ed0a87..5a03e525d 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 @@ -35,7 +35,7 @@ public interface AiMusicService { * * @param updateReqVO 更新信息 */ - void updateMusicPublicStatus(@Valid AiMusicUpdatePublicStatusReqVO updateReqVO); + void updateMusic(@Valid AiMusicUpdateReqVO updateReqVO); /** * 更新音乐名称 @@ -83,4 +83,5 @@ public interface AiMusicService { * @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 fb56fb4b0..7aa04d572 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 @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.music.AiMusicDO; import cn.iocoder.yudao.module.ai.dal.mysql.music.AiMusicMapper; import cn.iocoder.yudao.module.ai.enums.music.AiMusicGenerateModeEnum; import cn.iocoder.yudao.module.ai.enums.music.AiMusicStatusEnum; +import cn.iocoder.yudao.module.ai.service.model.AiApiKeyService; import cn.iocoder.yudao.module.infra.api.file.FileApi; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; @@ -35,7 +36,7 @@ import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.MUSIC_NOT_EXIS public class AiMusicServiceImpl implements AiMusicService { @Resource - private SunoApi sunoApi; + private AiApiKeyService apiKeyService; @Resource private AiMusicMapper musicMapper; @@ -46,6 +47,8 @@ public class AiMusicServiceImpl implements AiMusicService { @Override public List generateMusic(Long userId, AiSunoGenerateReqVO reqVO) { // 1. 调用 Suno 生成音乐 + SunoApi sunoApi = apiKeyService.getSunoApi(); + // TODO @xin:这两个貌似一直没跑成功,你那可以么?用的请求是 AiMusicController.http 的 List musicDataList; if (Objects.equals(AiMusicGenerateModeEnum.LYRIC.getMode(), reqVO.getGenerateMode())) { // 1.1 歌词模式 @@ -80,6 +83,7 @@ public class AiMusicServiceImpl implements AiMusicService { log.info("[syncMusic][Suno 开始同步, 共 ({}) 个任务]", streamingTask.size()); // GET 请求,为避免参数过长,分批次处理 + SunoApi sunoApi = apiKeyService.getSunoApi(); CollUtil.split(streamingTask, 36).forEach(chunkList -> { Map taskIdMap = convertMap(chunkList, AiMusicDO::getTaskId, AiMusicDO::getId); List musicTaskList = sunoApi.getMusicList(new ArrayList<>(taskIdMap.keySet())); @@ -96,7 +100,7 @@ public class AiMusicServiceImpl implements AiMusicService { } @Override - public void updateMusicPublicStatus(AiMusicUpdatePublicStatusReqVO updateReqVO) { + public void updateMusic(AiMusicUpdateReqVO updateReqVO) { // 校验存在 validateMusicExists(updateReqVO.getId()); // 更新 @@ -152,11 +156,16 @@ public class AiMusicServiceImpl implements AiMusicService { * @return AiMusicDO 集合 */ private List buildMusicDOList(List musicList) { + // TODO @xin:它有 status = error 状态,表示失败噢。 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)) + // TODO @xin:只有在完成的状态,在下载文件 + .setAudioUrl(downloadFile(musicData.audioUrl())) + .setVideoUrl(downloadFile(musicData.videoUrl())) + .setImageUrl(downloadFile(musicData.imageUrl())) + .setTitle(musicData.title()).setDuration(musicData.duration()) + .setLyric(musicData.lyric()).setTags(StrUtil.split(musicData.tags(), StrPool.COMMA)) .setStatus(Objects.equals("complete", musicData.status()) ? AiMusicStatusEnum.SUCCESS.getStatus() : AiMusicStatusEnum.IN_PROGRESS.getStatus())); } @@ -167,12 +176,17 @@ public class AiMusicServiceImpl implements AiMusicService { * @param url 音频文件地址 * @return 内部文件地址 */ - private String createFile(String url) { + private String downloadFile(String url) { if (StrUtil.isBlank(url)) { return null; } - byte[] bytes = HttpUtil.downloadBytes(url); - return fileApi.createFile(bytes); + try { + byte[] bytes = HttpUtil.downloadBytes(url); + return fileApi.createFile(bytes); + } catch (Exception e) { + log.error("[downloadFile][url({}) 下载失败]", url, e); + return url; + } } /** diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactory.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactory.java index ab7e7f996..e6e2cfddc 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactory.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactory.java @@ -1,6 +1,7 @@ package cn.iocoder.yudao.framework.ai.core.factory; import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; import org.springframework.ai.chat.StreamingChatClient; import org.springframework.ai.image.ImageClient; @@ -55,4 +56,15 @@ public interface AiClientFactory { */ ImageClient getOrCreateImageClient(AiPlatformEnum platform, String apiKey, String url); + /** + * 基于指定配置,获得 SunoApi 对象 + * + * 如果不存在,则进行创建 + * + * @param apiKey API KEY + * @param url API URL + * @return SunoApi 对象 + */ + SunoApi getOrCreateSunoApi(String apiKey, String url); + } diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java index b54b348b1..505d2bddc 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiClientFactoryImpl.java @@ -9,6 +9,7 @@ import cn.hutool.extra.spring.SpringUtil; import cn.iocoder.yudao.framework.ai.config.YudaoAiAutoConfiguration; import cn.iocoder.yudao.framework.ai.config.YudaoAiProperties; import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; +import cn.iocoder.yudao.framework.ai.core.model.suno.api.SunoApi; import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatClient; import cn.iocoder.yudao.framework.ai.core.model.tongyi.QianWenChatModal; import cn.iocoder.yudao.framework.ai.core.model.tongyi.api.QianWenApi; @@ -109,6 +110,11 @@ public class AiClientFactoryImpl implements AiClientFactory { } } + @Override + public SunoApi getOrCreateSunoApi(String apiKey, String url) { + return new SunoApi(url); + } + private static String buildClientCacheKey(Class clazz, Object... params) { if (ArrayUtil.isEmpty(params)) { return clazz.getName(); diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index de08d7965..b0b1d9b1e 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-55ishh05u-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 --- #################### 芋道相关配置 ####################