前端优化
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.tik.userprompt.controller.app;
|
||||
package cn.iocoder.yudao.module.tik.userprompt.controller;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
@@ -23,7 +23,7 @@ import static cn.iocoder.yudao.module.tik.enums.ErrorCodeConstants.USER_PROMPT_N
|
||||
|
||||
@Tag(name = "用户 App - 用户提示词")
|
||||
@RestController
|
||||
@RequestMapping("/ai/user-prompt")
|
||||
@RequestMapping("/api/ai/user-prompt")
|
||||
@Validated
|
||||
public class AppUserPromptController {
|
||||
|
||||
@@ -29,17 +29,16 @@ public class UserPromptServiceImpl implements UserPromptService {
|
||||
|
||||
@Override
|
||||
public Long createUserPrompt(UserPromptSaveReqVO createReqVO) {
|
||||
// 插入
|
||||
UserPromptDO userPrompt = BeanUtils.toBean(createReqVO, UserPromptDO.class);
|
||||
if (userPrompt.getSort() == null) userPrompt.setSort(0);
|
||||
if (userPrompt.getUseCount() == null) userPrompt.setUseCount(0);
|
||||
if (userPrompt.getIsPublic() == null) userPrompt.setIsPublic(false);
|
||||
userPromptMapper.insert(userPrompt);
|
||||
|
||||
// 返回
|
||||
return userPrompt.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUserPrompt(UserPromptSaveReqVO updateReqVO) {
|
||||
// 1. 手动验证前端表单字段(与前端表单对应)
|
||||
if (updateReqVO.getName() == null || updateReqVO.getName().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("提示词名称不能为空");
|
||||
}
|
||||
@@ -49,42 +48,32 @@ public class UserPromptServiceImpl implements UserPromptService {
|
||||
if (updateReqVO.getStatus() == null) {
|
||||
throw new IllegalArgumentException("状态不能为空");
|
||||
}
|
||||
|
||||
// 2. 校验存在并获取现有记录
|
||||
|
||||
UserPromptDO existing = validateUserPromptExists(updateReqVO.getId());
|
||||
|
||||
// 3. 手动设置要更新的字段(只更新前端表单中的字段)
|
||||
UserPromptDO updateObj = new UserPromptDO();
|
||||
updateObj.setId(updateReqVO.getId());
|
||||
updateObj.setName(updateReqVO.getName().trim());
|
||||
updateObj.setContent(updateReqVO.getContent().trim());
|
||||
updateObj.setCategory(updateReqVO.getCategory() != null ? updateReqVO.getCategory().trim() : null);
|
||||
updateObj.setStatus(updateReqVO.getStatus());
|
||||
|
||||
// 4. 自动填充前端表单中没有的字段(从数据库获取)
|
||||
updateObj.setSort(existing.getSort());
|
||||
updateObj.setUseCount(existing.getUseCount());
|
||||
updateObj.setIsPublic(existing.getIsPublic());
|
||||
updateObj.setUserId(existing.getUserId()); // 保持用户ID不变
|
||||
|
||||
// 5. 执行更新
|
||||
updateObj.setUserId(existing.getUserId());
|
||||
|
||||
userPromptMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUserPrompt(Long id) {
|
||||
// 校验存在
|
||||
validateUserPromptExists(id);
|
||||
// 删除
|
||||
userPromptMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUserPromptListByIds(List<Long> ids) {
|
||||
// 删除
|
||||
public void deleteUserPromptListByIds(List<Long> ids) {
|
||||
userPromptMapper.deleteByIds(ids);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private UserPromptDO validateUserPromptExists(Long id) {
|
||||
UserPromptDO userPrompt = userPromptMapper.selectById(id);
|
||||
@@ -103,5 +92,4 @@ public class UserPromptServiceImpl implements UserPromptService {
|
||||
public PageResult<UserPromptDO> getUserPromptPage(UserPromptPageReqVO pageReqVO) {
|
||||
return userPromptMapper.selectPage(pageReqVO);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,16 +27,13 @@ public class UserPromptSaveReqVO {
|
||||
@Schema(description = "分类/标签")
|
||||
private String category;
|
||||
|
||||
@Schema(description = "是否公开(0-私有,1-公开)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "是否公开(0-私有,1-公开)不能为空")
|
||||
@Schema(description = "是否公开(0-私有,1-公开)")
|
||||
private Boolean isPublic;
|
||||
|
||||
@Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotNull(message = "排序不能为空")
|
||||
@Schema(description = "排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "使用次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "22185")
|
||||
@NotNull(message = "使用次数不能为空")
|
||||
@Schema(description = "使用次数")
|
||||
private Integer useCount;
|
||||
|
||||
@Schema(description = "状态(0-禁用,1-启用)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
|
||||
@@ -16,7 +16,9 @@ import cn.iocoder.yudao.module.tik.file.dal.dataobject.TikUserFileDO;
|
||||
import cn.iocoder.yudao.module.tik.file.dal.mysql.TikUserFileMapper;
|
||||
import cn.iocoder.yudao.module.tik.file.service.TikOssInitService;
|
||||
import cn.iocoder.yudao.module.tik.voice.dal.dataobject.TikDigitalHumanTaskDO;
|
||||
import cn.iocoder.yudao.module.tik.voice.dal.dataobject.TikUserVoiceDO;
|
||||
import cn.iocoder.yudao.module.tik.voice.dal.mysql.TikDigitalHumanTaskMapper;
|
||||
import cn.iocoder.yudao.module.tik.voice.dal.mysql.TikUserVoiceMapper;
|
||||
import cn.iocoder.yudao.module.tik.voice.enums.DigitalHumanTaskStatusEnum;
|
||||
import cn.iocoder.yudao.module.tik.voice.enums.DigitalHumanTaskStepEnum;
|
||||
import cn.iocoder.yudao.module.tik.voice.vo.*;
|
||||
@@ -48,6 +50,7 @@ public class DigitalHumanTaskServiceImpl implements DigitalHumanTaskService {
|
||||
|
||||
private final TikDigitalHumanTaskMapper taskMapper;
|
||||
private final TikUserFileMapper userFileMapper;
|
||||
private final TikUserVoiceMapper userVoiceMapper;
|
||||
private final FileMapper fileMapper;
|
||||
private final FileApi fileApi;
|
||||
private final TikUserVoiceService userVoiceService;
|
||||
@@ -224,9 +227,21 @@ public class DigitalHumanTaskServiceImpl implements DigitalHumanTaskService {
|
||||
throw new IllegalArgumentException("文案不能为空");
|
||||
}
|
||||
|
||||
// 验证音色ID(必填)
|
||||
if (StrUtil.isBlank(reqVO.getVoiceId())) {
|
||||
throw new IllegalArgumentException("音色ID不能为空");
|
||||
// 验证音色参数(二选一:voiceId用于系统音色,voiceConfigId用于用户音色)
|
||||
boolean hasVoiceId = StrUtil.isNotBlank(reqVO.getVoiceId());
|
||||
boolean hasVoiceConfigId = reqVO.getVoiceConfigId() != null;
|
||||
|
||||
if (!hasVoiceId && !hasVoiceConfigId) {
|
||||
throw new IllegalArgumentException("必须提供音色ID(voiceId或voiceConfigId)");
|
||||
}
|
||||
|
||||
if (hasVoiceId && hasVoiceConfigId) {
|
||||
throw new IllegalArgumentException("voiceId和voiceConfigId不能同时提供");
|
||||
}
|
||||
|
||||
// 如果是用户音色,验证voiceConfigId对应的用户音色是否存在
|
||||
if (hasVoiceConfigId) {
|
||||
validateUserVoice(reqVO.getVoiceConfigId(), userId);
|
||||
}
|
||||
|
||||
// 验证视频文件(必填)
|
||||
@@ -253,17 +268,44 @@ public class DigitalHumanTaskServiceImpl implements DigitalHumanTaskService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证用户音色
|
||||
*/
|
||||
private void validateUserVoice(Long voiceConfigId, Long userId) {
|
||||
TikUserVoiceDO userVoice = userVoiceMapper.selectById(voiceConfigId);
|
||||
if (userVoice == null) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.GENERAL_NOT_EXISTS, "用户音色不存在");
|
||||
}
|
||||
|
||||
if (!userVoice.getUserId().equals(userId)) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.GENERAL_FORBIDDEN, "无权访问该音色");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(userVoice.getVoiceId())) {
|
||||
throw new IllegalArgumentException("该音色配置无效,缺少voiceId");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建任务记录
|
||||
*/
|
||||
private TikDigitalHumanTaskDO createTaskRecord(AppTikDigitalHumanCreateReqVO reqVO, Long userId) {
|
||||
// 如果是用户音色,需要从voiceConfigId获取voiceId
|
||||
String voiceId = reqVO.getVoiceId();
|
||||
if (voiceId == null && reqVO.getVoiceConfigId() != null) {
|
||||
TikUserVoiceDO userVoice = userVoiceMapper.selectById(reqVO.getVoiceConfigId());
|
||||
if (userVoice != null) {
|
||||
voiceId = userVoice.getVoiceId();
|
||||
}
|
||||
}
|
||||
|
||||
return TikDigitalHumanTaskDO.builder()
|
||||
.userId(userId)
|
||||
.taskName(reqVO.getTaskName())
|
||||
.aiProvider(StrUtil.blankToDefault(reqVO.getAiProvider(), "302ai"))
|
||||
.videoFileId(reqVO.getVideoFileId())
|
||||
.videoUrl(reqVO.getVideoUrl())
|
||||
.voiceId(reqVO.getVoiceId())
|
||||
.voiceId(voiceId)
|
||||
.inputText(reqVO.getInputText())
|
||||
.speechRate(reqVO.getSpeechRate() != null ? reqVO.getSpeechRate() : 1.0f)
|
||||
.volume(reqVO.getVolume() != null ? reqVO.getVolume() : 0f)
|
||||
|
||||
@@ -33,9 +33,12 @@ public class AppTikDigitalHumanCreateReqVO {
|
||||
@Size(max = 1024, message = "视频URL不能超过1024个字符")
|
||||
private String videoUrl;
|
||||
|
||||
@Schema(description = "音色ID(CosyVoice voiceId)", example = "cosyvoice-v3-flash-sys-xxx")
|
||||
@Schema(description = "音色ID(CosyVoice voiceId,系统音色使用)", example = "cosyvoice-v3-flash-sys-xxx")
|
||||
private String voiceId;
|
||||
|
||||
@Schema(description = "用户音色配置ID(tik_user_voice.id,用户音色使用)", example = "123")
|
||||
private Long voiceConfigId;
|
||||
|
||||
@Schema(description = "输入文本(用于语音合成,文案必填)", example = "您好,欢迎体验数字人")
|
||||
@NotBlank(message = "文案不能为空")
|
||||
@Size(max = 4000, message = "文本不能超过4000个字符")
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.tik.voice.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import org.eclipse.angus.mail.iap.ByteArray;
|
||||
|
||||
/**
|
||||
* Latentsync 任务结果响应 VO
|
||||
@@ -21,6 +22,10 @@ public class AppTikLatentsyncResultRespVO {
|
||||
@Schema(description = "视频信息")
|
||||
private VideoInfo video;
|
||||
|
||||
@Schema(description = "视频流信息")
|
||||
private ByteArray value;
|
||||
|
||||
|
||||
@Schema(description = "视频信息")
|
||||
@Data
|
||||
public static class VideoInfo {
|
||||
|
||||
Reference in New Issue
Block a user