【代码评审】AI:音乐接入

This commit is contained in:
YunaiV 2024-06-23 12:37:28 +08:00
parent 69b05a30bd
commit 75a91a2c46
10 changed files with 26 additions and 19 deletions

View File

@ -12,6 +12,7 @@ import lombok.Getter;
@Getter @Getter
public enum AiMusicGenerateEnum { public enum AiMusicGenerateEnum {
// TODO @xin用数字哈项目目前枚举都是数字
LYRIC("lyric", "歌词模式"), LYRIC("lyric", "歌词模式"),
DESCRIPTION("description", "描述模式"); DESCRIPTION("description", "描述模式");
@ -32,4 +33,5 @@ public enum AiMusicGenerateEnum {
} }
throw new IllegalArgumentException("未知模式: " + mode); throw new IllegalArgumentException("未知模式: " + mode);
} }
} }

View File

@ -12,6 +12,7 @@ import lombok.Getter;
@Getter @Getter
public enum AiMusicStatusEnum { public enum AiMusicStatusEnum {
// TODO @xin用数字哈项目目前枚举都是数字
// @xin 文档中无失败这个返回值 // @xin 文档中无失败这个返回值
STREAMING("streaming", "进行中"), STREAMING("streaming", "进行中"),
COMPLETE("complete", "完成"); COMPLETE("complete", "完成");

View File

@ -16,12 +16,13 @@ import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - AI 音乐生成") @Tag(name = "管理后台 - AI 音乐")
@RestController @RestController
@RequestMapping("/ai/music") @RequestMapping("/ai/music")
@RequiredArgsConstructor @RequiredArgsConstructor // TODO @xin通过 @Resource 注入哈
public class AiMusicController { public class AiMusicController {
// TODO @xin变量不用有 ai 前缀
private final AiMusicService aiMusicService; private final AiMusicService aiMusicService;
@PostMapping("/generate") @PostMapping("/generate")

View File

@ -6,7 +6,7 @@ import lombok.Data;
import java.util.List; import java.util.List;
// TODO @xin1ai 前缀2AiSunoGenerateReqVO要有生成哈3swaggger 缺少的属性也最好加下类似 example类上的 swagger
/** /**
* @author xiaoxin * @author xiaoxin
*/ */
@ -19,7 +19,8 @@ public class SunoReqVO {
@Schema(description = "是否纯音乐") @Schema(description = "是否纯音乐")
private Boolean makeInstrumental; private Boolean makeInstrumental;
@Schema(description = "模型版本 ") // TODO @xin我们自己是不是用 modelVersion还是什么梗精准减少非必要的缩写
@Schema(description = "模型版本")
private String mv; private String mv;
@Schema(description = "音乐风格") @Schema(description = "音乐风格")

View File

@ -12,6 +12,7 @@ import lombok.Data;
import java.util.List; import java.util.List;
// TODO @xin注释完善下
/** /**
* @Author xiaoxin * @Author xiaoxin
* @Date 2024/6/5 * @Date 2024/6/5
@ -94,7 +95,6 @@ public class AiMusicDO extends BaseDO {
*/ */
private String errorMessage; private String errorMessage;
/** /**
* 音乐风格标签 * 音乐风格标签
*/ */
@ -106,7 +106,7 @@ public class AiMusicDO extends BaseDO {
*/ */
private String taskId; private String taskId;
// TODO @xin @TableField(typeHandler = JacksonTypeHandler.class) 替代即可
public static class AiMusicTagsHandler extends AbstractJsonTypeHandler<Object> { public static class AiMusicTagsHandler extends AbstractJsonTypeHandler<Object> {
@Override @Override

View File

@ -15,6 +15,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
// TODO @xin不要直接叫这个名字哈要有它的目的
/** /**
* 处理 Suno Job * 处理 Suno Job
* @author xiaoxin * @author xiaoxin
@ -30,6 +31,7 @@ public class SunoJob implements JobHandler {
@Override @Override
public String execute(String param) { public String execute(String param) {
// TODO @xin可以考虑整个逻辑都下沉到 Service 有点类似 AccessLogCleanJob
List<AiMusicDO> unCompletedTask = musicService.getUnCompletedTask(); List<AiMusicDO> unCompletedTask = musicService.getUnCompletedTask();
if (CollUtil.isEmpty(unCompletedTask)) { if (CollUtil.isEmpty(unCompletedTask)) {

View File

@ -30,8 +30,10 @@ public class AiMusicConvert {
.setTags(StrUtil.isNotBlank(musicData.tags()) ? List.of(musicData.tags().split(StrPool.COMMA)) : null); .setTags(StrUtil.isNotBlank(musicData.tags()) ? List.of(musicData.tags().split(StrPool.COMMA)) : null);
} }
public static List<AiMusicDO> convertFrom(List<SunoApi.MusicData> musicDataList) { // TODO @xin一般情况下不用 convert直接逻辑里 convert 就好啦
return musicDataList.stream() public static List<AiMusicDO> convertFrom(List<SunoApi.MusicData> list) {
// TODO @xin可以使用 CollectionUtils.convertList 简洁一点
return list.stream()
.map(AiMusicConvert::convertFrom) .map(AiMusicConvert::convertFrom)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }

View File

@ -12,7 +12,6 @@ import java.util.List;
*/ */
public interface AiMusicService { public interface AiMusicService {
/** /**
* 音乐生成 * 音乐生成
* *
@ -21,7 +20,6 @@ public interface AiMusicService {
*/ */
List<Long> generateMusic(SunoReqVO reqVO); List<Long> generateMusic(SunoReqVO reqVO);
/** /**
* 获取未完成状态的任务 * 获取未完成状态的任务
* *
@ -29,8 +27,6 @@ public interface AiMusicService {
*/ */
List<AiMusicDO> getUnCompletedTask(); List<AiMusicDO> getUnCompletedTask();
Boolean updateBatch(List<AiMusicDO> aiMusicDOList); Boolean updateBatch(List<AiMusicDO> aiMusicDOList);
} }

View File

@ -21,6 +21,7 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
/** /**
* AI 音乐 Service 实现类 * AI 音乐 Service 实现类
*
* @author xiaoxin * @author xiaoxin
*/ */
@Service @Service
@ -29,11 +30,13 @@ public class AiMusicServiceImpl implements AiMusicService {
@Resource @Resource
private SunoApi sunoApi; private SunoApi sunoApi;
@Resource @Resource
private AiMusicMapper musicMapper; private AiMusicMapper musicMapper;
@Override @Override
public List<Long> generateMusic(SunoReqVO reqVO) { public List<Long> generateMusic(SunoReqVO reqVO) {
// TODO @xin是不是可以 if else 调用对应的 API然后 insertMusicData 逻辑
AiMusicGenerateEnum generateEnum = AiMusicGenerateEnum.valueOfMode(reqVO.getGenerateMode()); AiMusicGenerateEnum generateEnum = AiMusicGenerateEnum.valueOfMode(reqVO.getGenerateMode());
return switch (generateEnum) { return switch (generateEnum) {
case DESCRIPTION -> descriptionMode(reqVO); case DESCRIPTION -> descriptionMode(reqVO);

View File

@ -19,8 +19,8 @@ import java.util.function.Predicate;
/** /**
* Suno API * Suno API
* <b> *
* 文档地址https://github.com/status2xx/suno-api/blob/main/README_CN.md * 对接 Suno Proxy<a href="https://github.com/gcui-art/suno-api">suno-api</a>
* *
* @author xiaoxin * @author xiaoxin
*/ */
@ -31,14 +31,14 @@ public class SunoApi {
private final Predicate<HttpStatusCode> STATUS_PREDICATE = status -> !status.is2xxSuccessful(); private final Predicate<HttpStatusCode> STATUS_PREDICATE = status -> !status.is2xxSuccessful();
private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION = reqParam -> response -> response.bodyToMono(String.class) private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION =
.handle((respBody, sink) -> { reqParam -> response -> response.bodyToMono(String.class).handle((responseBody, sink) -> {
HttpRequest request = response.request(); HttpRequest request = response.request();
log.error("[suno-api] 调用失败!请求方式:[{}], 请求地址:[{}], 请求参数:[{}], 响应数据: [{}]", request.getMethod(), request.getURI(), reqParam, respBody); log.error("[suno-api] 调用失败!请求方式:[{}],请求地址:[{}],请求参数:[{}],响应数据: [{}]",
request.getMethod(), request.getURI(), reqParam, responseBody);
sink.error(new IllegalStateException("[suno-api] 调用失败!")); sink.error(new IllegalStateException("[suno-api] 调用失败!"));
}); });
public SunoApi(String baseUrl) { public SunoApi(String baseUrl) {
this.webClient = WebClient.builder() this.webClient = WebClient.builder()
.baseUrl(baseUrl) .baseUrl(baseUrl)
@ -111,7 +111,6 @@ public class SunoApi {
.block(); .block();
} }
/** /**
* 根据提示生成音频 * 根据提示生成音频
* *