Compare commits
2 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
8a4c0f73c6 | |
|
|
3a05e41f79 |
|
|
@ -10,10 +10,10 @@ import com.ruoyi.common.annotation.Anonymous;
|
||||||
import com.ruoyi.common.core.controller.BaseController;
|
import com.ruoyi.common.core.controller.BaseController;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.core.domain.model.LoginAiUser;
|
import com.ruoyi.common.core.domain.model.LoginAiUser;
|
||||||
import com.ruoyi.common.utils.AwsS3Util;
|
|
||||||
import com.ruoyi.common.utils.RandomStringUtil;
|
import com.ruoyi.common.utils.RandomStringUtil;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.common.utils.TencentCosUtil;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
@ -36,13 +36,21 @@ import java.util.regex.Pattern;
|
||||||
public class ByteApiController extends BaseController {
|
public class ByteApiController extends BaseController {
|
||||||
|
|
||||||
private final IByteService byteService;
|
private final IByteService byteService;
|
||||||
private final AwsS3Util awsS3Util;
|
private final TencentCosUtil tencentCosUtil;
|
||||||
private final IAiOrderService aiOrderService;
|
private final IAiOrderService aiOrderService;
|
||||||
private final IAiManagerService managerService;
|
private final IAiManagerService managerService;
|
||||||
private final IAiTagService aiTagService;
|
private final IAiTagService aiTagService;
|
||||||
@Value("${byteapi.callBackUrl}")
|
@Value("${byteapi.callBackUrl}")
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
|
// 火山引擎配置
|
||||||
|
@Value("${volcengine.ark.apiKey}")
|
||||||
|
private String volcApiKey;
|
||||||
|
@Value("${volcengine.ark.baseUrl}")
|
||||||
|
private String volcBaseUrl;
|
||||||
|
@Value("${volcengine.ark.callbackUrl}")
|
||||||
|
private String volcCallbackUrl;
|
||||||
|
|
||||||
@PostMapping("/promptToImg")
|
@PostMapping("/promptToImg")
|
||||||
@ApiOperation("文生图")
|
@ApiOperation("文生图")
|
||||||
public AjaxResult promptToImg(@RequestBody ByteApiRequest request) {
|
public AjaxResult promptToImg(@RequestBody ByteApiRequest request) {
|
||||||
|
|
@ -51,9 +59,12 @@ public class ByteApiController extends BaseController {
|
||||||
return AjaxResult.error("functionType is null");
|
return AjaxResult.error("functionType is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String mode = request.getMode() != null ? request.getMode() : "image-to-video";
|
||||||
AiManager aiManager = managerService.selectAiManagerByType(functionType);
|
AiManager aiManager = managerService.selectAiManagerByType(functionType);
|
||||||
String tags = request.getTags();
|
String tags = request.getTags();
|
||||||
String text = "";
|
String text = request.getText();
|
||||||
|
|
||||||
|
// 如果使用标签系统生成prompt
|
||||||
if (StringUtils.isNotEmpty(tags)) {
|
if (StringUtils.isNotEmpty(tags)) {
|
||||||
List<AiTag> aiTags = aiTagService.selectAiTagListByIds(request.getTags(), aiManager.getParentIdSort());
|
List<AiTag> aiTags = aiTagService.selectAiTagListByIds(request.getTags(), aiManager.getParentIdSort());
|
||||||
List<String> tagPrompts = new ArrayList<>();
|
List<String> tagPrompts = new ArrayList<>();
|
||||||
|
|
@ -70,22 +81,29 @@ public class ByteApiController extends BaseController {
|
||||||
tagPrompts.add(p);
|
tagPrompts.add(p);
|
||||||
}
|
}
|
||||||
text = StringUtils.replacePlaceholders(aiManager.getPrompt(), tagPrompts);
|
text = StringUtils.replacePlaceholders(aiManager.getPrompt(), tagPrompts);
|
||||||
} else {
|
|
||||||
text = aiManager.getPrompt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isEmpty(text)) {
|
if (StringUtils.isEmpty(text)) {
|
||||||
return AjaxResult.error("text is null");
|
return AjaxResult.error("text is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AiOrder aiOrder = aiOrderService.getAiOrder(functionType);
|
AiOrder aiOrder = aiOrderService.getAiOrder(functionType);
|
||||||
try {
|
try {
|
||||||
if (aiOrder == null) {
|
if (aiOrder == null) {
|
||||||
return AjaxResult.error(-1, "You have a low balance, please recharge");
|
return AjaxResult.error(-1, "You have a low balance, please recharge");
|
||||||
}
|
}
|
||||||
aiOrder.setText(text);
|
aiOrder.setText(text);
|
||||||
|
aiOrder.setFunctionType(mode); // 记录生成模式
|
||||||
|
|
||||||
|
// 文生视频模式下不设置图片
|
||||||
|
if ("image-to-video".equals(mode) && firstUrl != null) {
|
||||||
|
aiOrder.setImg1(firstUrl.toString());
|
||||||
|
}
|
||||||
|
|
||||||
ByteBodyReq byteBodyReq = new ByteBodyReq();
|
ByteBodyReq byteBodyReq = new ByteBodyReq();
|
||||||
byteBodyReq.setModel("ep-20251104104536-2gpgz");
|
// model由前端传入,默认为Seedance 2.0
|
||||||
|
byteBodyReq.setModel(StringUtils.isNotEmpty(request.getModel()) ?
|
||||||
|
request.getModel() : "ep-20260326165811-dlkth");
|
||||||
byteBodyReq.setPrompt(text);
|
byteBodyReq.setPrompt(text);
|
||||||
byteBodyReq.setSequential_image_generation("disabled");
|
byteBodyReq.setSequential_image_generation("disabled");
|
||||||
byteBodyReq.setResponse_format("url");
|
byteBodyReq.setResponse_format("url");
|
||||||
|
|
@ -96,7 +114,7 @@ public class ByteApiController extends BaseController {
|
||||||
List<ByteDataRes> data = byteBodyRes.getData();
|
List<ByteDataRes> data = byteBodyRes.getData();
|
||||||
ByteDataRes byteDataRes = data.get(0);
|
ByteDataRes byteDataRes = data.get(0);
|
||||||
String url = byteDataRes.getUrl();
|
String url = byteDataRes.getUrl();
|
||||||
url = awsS3Util.uploadFileByUrl(url);
|
url = tencentCosUtil.uploadFileByUrl(url);
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
// 判断生成失败,退回金额逻辑
|
// 判断生成失败,退回金额逻辑
|
||||||
aiOrderService.orderFailure(aiOrder);
|
aiOrderService.orderFailure(aiOrder);
|
||||||
|
|
@ -175,7 +193,7 @@ public class ByteApiController extends BaseController {
|
||||||
List<ByteDataRes> data = byteBodyRes.getData();
|
List<ByteDataRes> data = byteBodyRes.getData();
|
||||||
ByteDataRes byteDataRes = data.get(0);
|
ByteDataRes byteDataRes = data.get(0);
|
||||||
String url = byteDataRes.getUrl();
|
String url = byteDataRes.getUrl();
|
||||||
url = awsS3Util.uploadFileByUrl(url);
|
url = tencentCosUtil.uploadFileByUrl(url);
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
// 判断生成失败,退回金额逻辑
|
// 判断生成失败,退回金额逻辑
|
||||||
aiOrderService.orderFailure(aiOrder);
|
aiOrderService.orderFailure(aiOrder);
|
||||||
|
|
@ -191,7 +209,7 @@ public class ByteApiController extends BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/imgToVideo")
|
@PostMapping("/imgToVideo")
|
||||||
@ApiOperation("图生视频")
|
@ApiOperation("图生视频 (Seedance 2.0)")
|
||||||
public AjaxResult imgToVideo(@RequestBody ByteApiRequest request) throws Exception {
|
public AjaxResult imgToVideo(@RequestBody ByteApiRequest request) throws Exception {
|
||||||
String functionType = request.getFunctionType();
|
String functionType = request.getFunctionType();
|
||||||
if (null == functionType) {
|
if (null == functionType) {
|
||||||
|
|
@ -235,51 +253,56 @@ public class ByteApiController extends BaseController {
|
||||||
return AjaxResult.error(-1, "You have a low balance, please recharge");
|
return AjaxResult.error(-1, "You have a low balance, please recharge");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// String text = request.getText();
|
|
||||||
// if (StringUtils.isBlank(text)) {
|
|
||||||
// return AjaxResult.error("text is null");
|
|
||||||
// }
|
|
||||||
// String tags = request.getTags();
|
|
||||||
// if (StringUtils.isNotBlank(tags)) {
|
|
||||||
// text = "(优先考虑以下关键词:" + tags + ")";
|
|
||||||
// }
|
|
||||||
aiOrder.setText(text);
|
aiOrder.setText(text);
|
||||||
|
|
||||||
aiOrder.setImg1(firstUrl.toString());
|
aiOrder.setImg1(firstUrl.toString());
|
||||||
Integer duration = request.getDuration();
|
|
||||||
|
Integer duration = request.getDuration() != null ? request.getDuration() : 4;
|
||||||
|
|
||||||
ByteBodyReq byteBodyReq = new ByteBodyReq();
|
ByteBodyReq byteBodyReq = new ByteBodyReq();
|
||||||
byteBodyReq.setModel("ep-20251113072240-cfxlz");
|
// model由前端传入,默认为Seedance2.0
|
||||||
byteBodyReq.setCallback_url(url + "/api/ai/callBack");
|
byteBodyReq.setModel(StringUtils.isNotEmpty(request.getModel()) ?
|
||||||
List<ContentItem> content = new ArrayList<>();
|
request.getModel() : "ep-20260326165811-dlkth");
|
||||||
ContentItem contentItem = new ContentItem();
|
byteBodyReq.setCallback_url(volcCallbackUrl);
|
||||||
contentItem.setType("text");
|
|
||||||
contentItem.setText(text + " --dur " + duration + " --fps 24 --rs 720p --wm false --cf false");
|
|
||||||
content.add(contentItem);
|
|
||||||
|
|
||||||
ContentItem contentItem1 = new ContentItem();
|
// 构建符合火山引擎格式的content
|
||||||
contentItem1.setType("image_url");
|
List<ContentItem> contentList = new ArrayList<>();
|
||||||
contentItem1.setRole("first_frame");
|
|
||||||
ImageUrl imageUrl1 = new ImageUrl();
|
|
||||||
imageUrl1.setUrl(firstUrl.toString());
|
|
||||||
contentItem1.setImageUrl(imageUrl1);
|
|
||||||
content.add(contentItem1);
|
|
||||||
|
|
||||||
|
// 文本提示词
|
||||||
|
ContentItem textItem = new ContentItem();
|
||||||
|
textItem.setType("text");
|
||||||
|
textItem.setText(text);
|
||||||
|
contentList.add(textItem);
|
||||||
|
|
||||||
|
// 首帧图片
|
||||||
|
ContentItem firstFrameItem = new ContentItem();
|
||||||
|
firstFrameItem.setType("image_url");
|
||||||
|
firstFrameItem.setRole("first_frame");
|
||||||
|
ImageUrl firstImageUrl = new ImageUrl();
|
||||||
|
firstImageUrl.setUrl(firstUrl.toString());
|
||||||
|
firstFrameItem.setImageUrl(firstImageUrl);
|
||||||
|
contentList.add(firstFrameItem);
|
||||||
|
|
||||||
|
// 如果有尾帧
|
||||||
String lastUrl = request.getLastUrl();
|
String lastUrl = request.getLastUrl();
|
||||||
if (StringUtils.isNotBlank(lastUrl)) {
|
if (StringUtils.isNotBlank(lastUrl)) {
|
||||||
ContentItem contentItem2 = new ContentItem();
|
ContentItem lastFrameItem = new ContentItem();
|
||||||
contentItem2.setType("image_url");
|
lastFrameItem.setType("image_url");
|
||||||
contentItem2.setRole("last_frame");
|
lastFrameItem.setRole("last_frame");
|
||||||
ImageUrl imageUrl2 = new ImageUrl();
|
ImageUrl lastImageUrl = new ImageUrl();
|
||||||
imageUrl2.setUrl(lastUrl);
|
lastImageUrl.setUrl(lastUrl);
|
||||||
contentItem2.setImageUrl(imageUrl2);
|
lastFrameItem.setImageUrl(lastImageUrl);
|
||||||
content.add(contentItem2);
|
contentList.add(lastFrameItem);
|
||||||
aiOrder.setImg2(lastUrl);
|
aiOrder.setImg2(lastUrl);
|
||||||
}
|
}
|
||||||
byteBodyReq.setContent(content);
|
|
||||||
|
byteBodyReq.setContent(contentList);
|
||||||
|
byteBodyReq.setDuration(duration);
|
||||||
|
byteBodyReq.setResolution("720p");
|
||||||
|
byteBodyReq.setRatio("3:4");
|
||||||
|
|
||||||
ByteBodyRes byteBodyRes = byteService.imgToVideo(byteBodyReq);
|
ByteBodyRes byteBodyRes = byteService.imgToVideo(byteBodyReq);
|
||||||
String id = byteBodyRes.getId();
|
String id = byteBodyRes.getId();
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
// 判断生成失败,退回金额逻辑
|
|
||||||
aiOrderService.orderFailure(aiOrder);
|
aiOrderService.orderFailure(aiOrder);
|
||||||
return AjaxResult.error(-2, "generation failed, balance has been refunded");
|
return AjaxResult.error(-2, "generation failed, balance has been refunded");
|
||||||
}
|
}
|
||||||
|
|
@ -299,7 +322,7 @@ public class ByteApiController extends BaseController {
|
||||||
if ("succeeded".equals(byteBodyRes.getStatus())) {
|
if ("succeeded".equals(byteBodyRes.getStatus())) {
|
||||||
content content = byteBodyRes.getContent();
|
content content = byteBodyRes.getContent();
|
||||||
String videoUrl = content.getVideo_url();
|
String videoUrl = content.getVideo_url();
|
||||||
videoUrl = awsS3Util.uploadFileByUrl(videoUrl);
|
videoUrl = tencentCosUtil.uploadFileByUrl(videoUrl);
|
||||||
content.setVideo_url(videoUrl);
|
content.setVideo_url(videoUrl);
|
||||||
AiOrder aiOrderByResult = aiOrderService.getAiOrderByResult(id);
|
AiOrder aiOrderByResult = aiOrderService.getAiOrderByResult(id);
|
||||||
AiOrder aiOrder = new AiOrder();
|
AiOrder aiOrder = new AiOrder();
|
||||||
|
|
@ -311,24 +334,34 @@ public class ByteApiController extends BaseController {
|
||||||
return AjaxResult.success(byteBodyRes);
|
return AjaxResult.success(byteBodyRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/callBack")
|
@GetMapping(value = "/volcCallback")
|
||||||
@ApiOperation("视频下载回调")
|
@ApiOperation("火山引擎视频回调")
|
||||||
@Anonymous
|
@Anonymous
|
||||||
public AjaxResult callBack(@PathVariable("id") ByteBodyRes byteBodyRes) throws Exception {
|
public AjaxResult volcCallback(@RequestBody ByteBodyRes byteBodyRes) throws Exception {
|
||||||
if ("succeeded".equals(byteBodyRes.getStatus())) {
|
if ("succeeded".equals(byteBodyRes.getStatus())) {
|
||||||
String id = byteBodyRes.getId();
|
String id = byteBodyRes.getId();
|
||||||
content content = byteBodyRes.getContent();
|
content contentObj = byteBodyRes.getContent();
|
||||||
String videoUrl = content.getVideo_url();
|
if (contentObj != null && StringUtils.isNotEmpty(contentObj.getVideo_url())) {
|
||||||
videoUrl = awsS3Util.uploadFileByUrl(videoUrl);
|
String videoUrl = contentObj.getVideo_url();
|
||||||
content.setVideo_url(videoUrl);
|
videoUrl = tencentCosUtil.uploadFileByUrl(videoUrl);
|
||||||
|
contentObj.setVideo_url(videoUrl);
|
||||||
|
|
||||||
AiOrder aiOrderByResult = aiOrderService.getAiOrderByResult(id);
|
AiOrder aiOrderByResult = aiOrderService.getAiOrderByResult(id);
|
||||||
|
if (aiOrderByResult != null) {
|
||||||
AiOrder aiOrder = new AiOrder();
|
AiOrder aiOrder = new AiOrder();
|
||||||
aiOrder.setId(aiOrderByResult.getId());
|
aiOrder.setId(aiOrderByResult.getId());
|
||||||
aiOrder.setResult(videoUrl);
|
aiOrder.setResult(videoUrl);
|
||||||
// aiOrder.setUpdateBy(SecurityUtils.getLoginAiUser().getUsername());
|
|
||||||
aiOrderService.updateAiOrder(aiOrder);
|
aiOrderService.updateAiOrder(aiOrder);
|
||||||
}
|
}
|
||||||
return AjaxResult.success(byteBodyRes);
|
}
|
||||||
|
}
|
||||||
|
return AjaxResult.success("callback success");
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping(value = "/{id}/cancel")
|
||||||
|
@ApiOperation("取消视频生成任务")
|
||||||
|
public AjaxResult cancelTask(@PathVariable("id") String id) throws Exception {
|
||||||
|
return byteService.cancelVideoTask(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.ruoyi.api;
|
package com.ruoyi.api;
|
||||||
|
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.utils.AwsS3Util;
|
import com.ruoyi.common.utils.TencentCosUtil;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import io.swagger.annotations.ApiParam;
|
import io.swagger.annotations.ApiParam;
|
||||||
|
|
@ -18,7 +18,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
@Api(tags = "文件上传")
|
@Api(tags = "文件上传")
|
||||||
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
@RequiredArgsConstructor(onConstructor_ = @Autowired)
|
||||||
public class FileController {
|
public class FileController {
|
||||||
private final AwsS3Util awsS3Util;
|
private final TencentCosUtil tencentCosUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件上传
|
* 文件上传
|
||||||
|
|
@ -30,7 +30,7 @@ public class FileController {
|
||||||
@ApiParam(name = "file", value = "文件", required = true)
|
@ApiParam(name = "file", value = "文件", required = true)
|
||||||
@RequestParam("file") MultipartFile file) throws Exception {
|
@RequestParam("file") MultipartFile file) throws Exception {
|
||||||
AjaxResult ajax = AjaxResult.success();
|
AjaxResult ajax = AjaxResult.success();
|
||||||
String uploadUrl = awsS3Util.uploadMultipartFile(file, true);
|
String uploadUrl = tencentCosUtil.uploadMultipartFile(file, true);
|
||||||
ajax.put("url", uploadUrl);
|
ajax.put("url", uploadUrl);
|
||||||
return ajax;
|
return ajax;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,11 @@ public class ByteApiRequest {
|
||||||
@ApiModelProperty(name = "标签字符串")
|
@ApiModelProperty(name = "标签字符串")
|
||||||
private String tags;
|
private String tags;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "使用的模型")
|
||||||
|
private String model;
|
||||||
|
|
||||||
|
@ApiModelProperty(name = "生成模式:text-to-video 或 image-to-video")
|
||||||
|
private String mode = "text-to-video";
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import com.ruoyi.common.annotation.Anonymous;
|
||||||
import com.ruoyi.common.config.RuoYiConfig;
|
import com.ruoyi.common.config.RuoYiConfig;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.exception.base.BaseException;
|
import com.ruoyi.common.exception.base.BaseException;
|
||||||
import com.ruoyi.common.utils.AwsS3Util;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.TencentCosUtil;
|
import com.ruoyi.common.utils.TencentCosUtil;
|
||||||
import com.ruoyi.common.utils.file.FileUploadUtils;
|
import com.ruoyi.common.utils.file.FileUploadUtils;
|
||||||
|
|
@ -36,7 +35,6 @@ public class CommonController {
|
||||||
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
|
private static final Logger log = LoggerFactory.getLogger(CommonController.class);
|
||||||
private final ServerConfig serverConfig;
|
private final ServerConfig serverConfig;
|
||||||
private final TencentCosUtil tencentCosUtil;
|
private final TencentCosUtil tencentCosUtil;
|
||||||
private final AwsS3Util awsS3Util;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通用下载请求
|
* 通用下载请求
|
||||||
|
|
@ -158,7 +156,7 @@ public class CommonController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AWS上传请求(单个)
|
* 腾讯云COS上传请求(单个)
|
||||||
*/
|
*/
|
||||||
@ApiOperation("图片上传接口")
|
@ApiOperation("图片上传接口")
|
||||||
@PostMapping("/aws/upload")
|
@PostMapping("/aws/upload")
|
||||||
|
|
@ -166,7 +164,7 @@ public class CommonController {
|
||||||
AjaxResult ajax = AjaxResult.success();
|
AjaxResult ajax = AjaxResult.success();
|
||||||
String uploadUrl;
|
String uploadUrl;
|
||||||
try {
|
try {
|
||||||
uploadUrl = awsS3Util.uploadMultipartFile(file, true);
|
uploadUrl = tencentCosUtil.uploadMultipartFile(file, true);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return AjaxResult.error(e.getMessage());
|
return AjaxResult.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -209,24 +209,32 @@ google:
|
||||||
redirect-uri:
|
redirect-uri:
|
||||||
|
|
||||||
tencentCos:
|
tencentCos:
|
||||||
accessKey:
|
accessKey: AKIDBE3dzBdLsHYfZLwKVSFArLchZDerrfHf
|
||||||
secretKey:
|
secretKey: EDyUmsnX2IJ5f0oRn1QdeQ0TmrtqgQ1c
|
||||||
endpoint:
|
endpoint: ap-guangzhou
|
||||||
bucketName:
|
bucketName: seedance-1331490964
|
||||||
domain:
|
domain: https://seedance-1331490964.cos.ap-guangzhou.myqcloud.com
|
||||||
|
|
||||||
aws:
|
# aws配置已替换为腾讯云COS,请在环境变量或配置文件中设置腾讯云凭证
|
||||||
accessKey: AKIAYVMHEVDDZQGE3HVX
|
# aws:
|
||||||
secretKey: B9nxdferMhdRuxzoKeQam/NxiVvIhI7lSru6VfwG
|
# accessKey: AKIAYVMHEVDDZQGE3HVX
|
||||||
endpoint: ap-southeast-1
|
# secretKey: B9nxdferMhdRuxzoKeQam/NxiVvIhI7lSru6VfwG
|
||||||
bucketName: di-image
|
# endpoint: ap-southeast-1
|
||||||
domain: https://images.iqyjsnwv.com/
|
# bucketName: di-image
|
||||||
|
# domain: https://images.iqyjsnwv.com/
|
||||||
|
|
||||||
byteapi:
|
byteapi:
|
||||||
url: https://ark.ap-southeast.bytepluses.com/api/v3
|
url: https://ark.ap-southeast.bytepluses.com/api/v3
|
||||||
apiKey: 327d2815-2516-44c2-9e32-2dc50bf7afd7
|
apiKey: 3e33e034-7e25-4228-8864-b51b2a7a8f97
|
||||||
callBackUrl: https://undressing.top
|
callBackUrl: https://undressing.top
|
||||||
|
|
||||||
|
# 火山引擎 Ark API (Seedance 2.0)
|
||||||
|
volcengine:
|
||||||
|
ark:
|
||||||
|
baseUrl: https://ark.cn-beijing.volces.com
|
||||||
|
apiKey: 3e33e034-7e25-4228-8864-b51b2a7a8f97
|
||||||
|
callbackUrl: https://undressing.top/api/ai/volcCallback
|
||||||
|
|
||||||
jinsha:
|
jinsha:
|
||||||
url: https://api.jinshapay.xyz
|
url: https://api.jinshapay.xyz
|
||||||
appId: 1763617360
|
appId: 1763617360
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,13 @@ import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
|
@ -33,22 +39,32 @@ public class TencentCosUtil {
|
||||||
private String domain;
|
private String domain;
|
||||||
|
|
||||||
|
|
||||||
//文件上传
|
/**
|
||||||
public String upload(MultipartFile file) {
|
* 上传MultipartFile到腾讯云COS,返回文件访问地址
|
||||||
|
* 与AwsS3Util.uploadMultipartFile方法接口兼容
|
||||||
|
*/
|
||||||
|
public String upload(MultipartFile file) throws Exception {
|
||||||
|
return uploadMultipartFile(file, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传MultipartFile到腾讯云COS,返回文件访问地址
|
||||||
|
*
|
||||||
|
* @param file 前端上传的MultipartFile
|
||||||
|
* @param isPublic 是否公开访问(当前实现中忽略,使用domain配置)
|
||||||
|
* @return 文件访问地址(URL字符串)
|
||||||
|
*/
|
||||||
|
public String uploadMultipartFile(MultipartFile file, boolean isPublic) throws Exception {
|
||||||
|
if (file.isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("上传文件不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
// 3 生成 cos 客户端。
|
|
||||||
COSClient cosClient = createCosClient();
|
COSClient cosClient = createCosClient();
|
||||||
|
|
||||||
// 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
|
// 生成唯一文件键,格式与AWS一致:yyyy/MM/dd/uuid_filename
|
||||||
// 对象键(Key)是对象在存储桶中的唯一标识。 998u-09iu-09i-333
|
String key = generateCosKey(file.getOriginalFilename());
|
||||||
//在文件名称前面添加uuid值
|
|
||||||
String key = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8) + "_"
|
|
||||||
+ file.getOriginalFilename();
|
|
||||||
//对上传文件分组,根据当前日期 /2022/11/11
|
|
||||||
String dateTime = new DateTime().toString("yyyy/MM/dd");
|
|
||||||
key = dateTime + "/" + key;
|
|
||||||
try {
|
try {
|
||||||
//获取上传文件输入流
|
|
||||||
InputStream inputStream = file.getInputStream();
|
InputStream inputStream = file.getInputStream();
|
||||||
ObjectMetadata objectMetadata = new ObjectMetadata();
|
ObjectMetadata objectMetadata = new ObjectMetadata();
|
||||||
PutObjectRequest putObjectRequest = new PutObjectRequest(
|
PutObjectRequest putObjectRequest = new PutObjectRequest(
|
||||||
|
|
@ -56,17 +72,41 @@ public class TencentCosUtil {
|
||||||
key,
|
key,
|
||||||
inputStream,
|
inputStream,
|
||||||
objectMetadata);
|
objectMetadata);
|
||||||
// 高级接口会返回一个异步结果Upload
|
|
||||||
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
|
PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
|
||||||
|
|
||||||
//返回上传文件路径
|
// 返回COS文件访问地址
|
||||||
//https://ggkt-atguigu-1310644373.cos.ap-beijing.myqcloud.com/01.jpg
|
String url = domain + (domain.endsWith("/") ? "" : "/") + key;
|
||||||
String url = domain + "/" + key;
|
|
||||||
return url;
|
return url;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
throw new RuntimeException("上传文件到COS失败: " + e.getMessage(), e);
|
||||||
|
} finally {
|
||||||
|
cosClient.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过URL下载文件并上传到COS
|
||||||
|
* 与AwsS3Util.uploadFileByUrl方法接口兼容
|
||||||
|
*/
|
||||||
|
public String uploadFileByUrl(String fileUrl) throws Exception {
|
||||||
|
return uploadFileByUrl(fileUrl, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String uploadFileByUrl(String fileUrl, boolean isPublic) throws Exception {
|
||||||
|
if (fileUrl == null || fileUrl.trim().isEmpty()) {
|
||||||
|
throw new IllegalArgumentException("文件下载链接不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
Path tempPath = downloadFileToTemp(fileUrl);
|
||||||
|
try {
|
||||||
|
// 使用临时文件上传
|
||||||
|
MultipartFile multipartFile = createMultipartFileFromPath(tempPath, extractFileNameFromUrl(fileUrl));
|
||||||
|
return uploadMultipartFile(multipartFile, isPublic);
|
||||||
|
} finally {
|
||||||
|
Files.deleteIfExists(tempPath);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -78,7 +118,107 @@ public class TencentCosUtil {
|
||||||
ClientConfig clientConfig = new ClientConfig(region);
|
ClientConfig clientConfig = new ClientConfig(region);
|
||||||
// 这里建议设置使用 https 协议
|
// 这里建议设置使用 https 协议
|
||||||
clientConfig.setHttpProtocol(HttpProtocol.https);
|
clientConfig.setHttpProtocol(HttpProtocol.https);
|
||||||
|
clientConfig.setConnectionTimeout(30 * 1000); // 连接超时30秒
|
||||||
|
clientConfig.setSocketTimeout(60 * 1000); // 读取超时60秒
|
||||||
//1.3 生成cos客户端
|
//1.3 生成cos客户端
|
||||||
return new COSClient(credentials, clientConfig);
|
return new COSClient(credentials, clientConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成COS文件键,与AWS保持一致的命名格式
|
||||||
|
*/
|
||||||
|
private String generateCosKey(String originalFileName) {
|
||||||
|
String uuid = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 8);
|
||||||
|
String dateTime = new DateTime().toString("yyyy/MM/dd");
|
||||||
|
return dateTime + "/" + uuid + "_" + originalFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载文件到临时路径
|
||||||
|
*/
|
||||||
|
private Path downloadFileToTemp(String fileUrl) throws Exception {
|
||||||
|
String suffix = getFileSuffixFromUrl(fileUrl);
|
||||||
|
Path tempPath = Files.createTempFile("url-upload-", suffix);
|
||||||
|
|
||||||
|
HttpURLConnection connection = null;
|
||||||
|
InputStream in = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL(fileUrl);
|
||||||
|
connection = (HttpURLConnection) url.openConnection();
|
||||||
|
connection.setRequestMethod("GET");
|
||||||
|
connection.setConnectTimeout(5000);
|
||||||
|
connection.setReadTimeout(10000);
|
||||||
|
|
||||||
|
int responseCode = connection.getResponseCode();
|
||||||
|
if (responseCode < 200 || responseCode >= 300) {
|
||||||
|
throw new RuntimeException("文件下载失败,状态码:" + responseCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
in = connection.getInputStream();
|
||||||
|
out = Files.newOutputStream(tempPath);
|
||||||
|
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = in.read(buffer)) != -1) {
|
||||||
|
out.write(buffer, 0, bytesRead);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (out != null) {
|
||||||
|
try { out.close(); } catch (IOException e) { e.printStackTrace(); }
|
||||||
|
}
|
||||||
|
if (in != null) {
|
||||||
|
try { in.close(); } catch (IOException e) { e.printStackTrace(); }
|
||||||
|
}
|
||||||
|
if (connection != null) {
|
||||||
|
connection.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tempPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractFileNameFromUrl(String fileUrl) {
|
||||||
|
String fileName = fileUrl.substring(fileUrl.lastIndexOf("/") + 1);
|
||||||
|
if (fileName.contains("?")) {
|
||||||
|
fileName = fileName.split("\\?")[0];
|
||||||
|
}
|
||||||
|
return fileName.isEmpty() ? "default_file" : fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFileSuffixFromUrl(String fileUrl) {
|
||||||
|
String fileName = extractFileNameFromUrl(fileUrl);
|
||||||
|
if (fileName.contains(".")) {
|
||||||
|
return fileName.substring(fileName.lastIndexOf("."));
|
||||||
|
}
|
||||||
|
return ".tmp";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将Path转换为MultipartFile(简单实现,用于uploadFileByUrl)
|
||||||
|
*/
|
||||||
|
private MultipartFile createMultipartFileFromPath(Path path, String originalFilename) throws IOException {
|
||||||
|
byte[] bytes = Files.readAllBytes(path);
|
||||||
|
return new MultipartFile() {
|
||||||
|
@Override
|
||||||
|
public String getName() { return "file"; }
|
||||||
|
@Override
|
||||||
|
public String getOriginalFilename() { return originalFilename; }
|
||||||
|
@Override
|
||||||
|
public String getContentType() { return null; }
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() { return bytes.length == 0; }
|
||||||
|
@Override
|
||||||
|
public long getSize() { return bytes.length; }
|
||||||
|
@Override
|
||||||
|
public byte[] getBytes() throws IOException { return bytes; }
|
||||||
|
@Override
|
||||||
|
public InputStream getInputStream() throws IOException { return Files.newInputStream(path); }
|
||||||
|
@Override
|
||||||
|
public void transferTo(java.io.File dest) throws IOException, IllegalStateException {
|
||||||
|
Files.copy(path, dest.toPath());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,22 @@ public class AiOrder extends BaseEntity {
|
||||||
@Excel(name = "是否置顶:N-否 Y-是")
|
@Excel(name = "是否置顶:N-否 Y-是")
|
||||||
private String isTop;
|
private String isTop;
|
||||||
|
|
||||||
|
/** 生成模式:text-to-video 或 image-to-video */
|
||||||
|
@Excel(name = "生成模式")
|
||||||
|
private String mode;
|
||||||
|
|
||||||
|
/** 视频时长(秒) */
|
||||||
|
@Excel(name = "视频时长")
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
/** 分辨率(如 720p, 1080p) */
|
||||||
|
@Excel(name = "分辨率")
|
||||||
|
private String resolution;
|
||||||
|
|
||||||
|
/** 宽高比(如 16:9, 9:16) */
|
||||||
|
@Excel(name = "宽高比")
|
||||||
|
private String ratio;
|
||||||
|
|
||||||
/** 首帧图片 */
|
/** 首帧图片 */
|
||||||
private String img1;
|
private String img1;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,5 +30,10 @@ public class ByteBodyReq {
|
||||||
@JsonProperty("content")
|
@JsonProperty("content")
|
||||||
private List<ContentItem> content;
|
private List<ContentItem> content;
|
||||||
|
|
||||||
|
private Integer duration;
|
||||||
|
private String resolution;
|
||||||
|
private String ratio;
|
||||||
|
private Integer seed;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.ruoyi.ai.service;
|
||||||
|
|
||||||
import com.ruoyi.ai.domain.ByteBodyReq;
|
import com.ruoyi.ai.domain.ByteBodyReq;
|
||||||
import com.ruoyi.ai.domain.ByteBodyRes;
|
import com.ruoyi.ai.domain.ByteBodyRes;
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
|
||||||
public interface IByteService {
|
public interface IByteService {
|
||||||
|
|
||||||
|
|
@ -24,4 +25,9 @@ public interface IByteService {
|
||||||
* 下载视频
|
* 下载视频
|
||||||
*/
|
*/
|
||||||
ByteBodyRes uploadVideo(String id) throws Exception;
|
ByteBodyRes uploadVideo(String id) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消视频生成任务
|
||||||
|
*/
|
||||||
|
AjaxResult cancelVideoTask(String id) throws Exception;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.ruoyi.ai.domain.ByteBodyReq;
|
import com.ruoyi.ai.domain.ByteBodyReq;
|
||||||
import com.ruoyi.ai.domain.ByteBodyRes;
|
import com.ruoyi.ai.domain.ByteBodyRes;
|
||||||
import com.ruoyi.ai.service.IByteService;
|
import com.ruoyi.ai.service.IByteService;
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.http.OkHttpUtils;
|
import com.ruoyi.common.utils.http.OkHttpUtils;
|
||||||
import okhttp3.*;
|
import okhttp3.*;
|
||||||
|
|
@ -30,6 +31,13 @@ public class ByteService implements IByteService {
|
||||||
@Value("${byteapi.apiKey}")
|
@Value("${byteapi.apiKey}")
|
||||||
private String apiKey;
|
private String apiKey;
|
||||||
|
|
||||||
|
// 火山引擎配置
|
||||||
|
@Value("${volcengine.ark.baseUrl:https://ark.cn-beijing.volces.com}")
|
||||||
|
private String volcBaseUrl;
|
||||||
|
|
||||||
|
@Value("${volcengine.ark.apiKey}")
|
||||||
|
private String volcApiKey;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBodyRes promptToImg(ByteBodyReq req) throws Exception {
|
public ByteBodyRes promptToImg(ByteBodyReq req) throws Exception {
|
||||||
return this.imgToImg(req);
|
return this.imgToImg(req);
|
||||||
|
|
@ -75,71 +83,92 @@ public class ByteService implements IByteService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBodyRes imgToVideo(ByteBodyReq req) throws Exception {
|
public ByteBodyRes imgToVideo(ByteBodyReq req) throws Exception {
|
||||||
|
if (req == null) {
|
||||||
|
throw new Exception("imgToVideo error:req is null");
|
||||||
|
}
|
||||||
|
|
||||||
// 1. 验证请求参数(可选,根据业务需求)
|
// 使用火山引擎配置
|
||||||
// if (StringUtils.isBlank(req.getPrompt())) {
|
|
||||||
// throw new Exception("imgToVideo error:prompt is null");
|
|
||||||
// }
|
|
||||||
|
|
||||||
// 2. 构建请求体JSON(基于ByteBodyReq的字段)
|
|
||||||
// 注意:ByteBodyReq需包含与API参数对应的字段(model、prompt等)
|
|
||||||
String jsonBody = objectMapper.writeValueAsString(req);
|
String jsonBody = objectMapper.writeValueAsString(req);
|
||||||
// 3. 构建请求
|
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(API_URL + "/contents/generations/tasks")
|
.url(volcBaseUrl + "/api/v3/contents/generations/tasks")
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.header("Authorization", "Bearer " + apiKey)
|
.header("Authorization", "Bearer " + volcApiKey)
|
||||||
.post(RequestBody.create(
|
.post(RequestBody.create(
|
||||||
MediaType.parse("application/json; charset=utf-8"),
|
MediaType.parse("application/json; charset=utf-8"),
|
||||||
jsonBody
|
jsonBody
|
||||||
))
|
))
|
||||||
.build();
|
.build();
|
||||||
// 4. 发送同步请求(因方法需要返回值,使用execute而非enqueue)
|
|
||||||
Response response = OkHttpUtils.newCall(request).execute();
|
Response response = OkHttpUtils.newCall(request).execute();
|
||||||
// 5. 处理响应
|
|
||||||
if (!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
// 非200状态:返回错误信息(假设ByteBodyRes有error字段)
|
|
||||||
String errorMsg = response.body() != null ? response.body().string() : "imgToVideo error";
|
String errorMsg = response.body() != null ? response.body().string() : "imgToVideo error";
|
||||||
throw new Exception("imgToVideo error:" + errorMsg);
|
throw new Exception("imgToVideo error:" + errorMsg);
|
||||||
}
|
}
|
||||||
// 6. 解析成功响应为ByteBodyRes
|
|
||||||
if (response.body() == null) {
|
if (response.body() == null) {
|
||||||
throw new Exception("imgToVideo response null");
|
throw new Exception("imgToVideo response null");
|
||||||
}
|
}
|
||||||
|
|
||||||
String responseBody = response.body().string();
|
String responseBody = response.body().string();
|
||||||
return objectMapper.readValue(responseBody, ByteBodyRes.class);
|
return objectMapper.readValue(responseBody, ByteBodyRes.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBodyRes uploadVideo(String id) throws Exception {
|
public ByteBodyRes uploadVideo(String id) throws Exception {
|
||||||
// 1. 验证请求参数(可选,根据业务需求)
|
|
||||||
if (StringUtils.isBlank(id)) {
|
if (StringUtils.isBlank(id)) {
|
||||||
throw new Exception("uploadVideo error:id is null");
|
throw new Exception("uploadVideo error:id is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 构建请求体JSON(基于ByteBodyReq的字段)
|
// 使用火山引擎配置查询任务状态
|
||||||
// 注意:ByteBodyReq需包含与API参数对应的字段(model、prompt等)
|
|
||||||
//String jsonBody = objectMapper.writeValueAsString(req);
|
|
||||||
// 3. 构建请求
|
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
.url(API_URL + "/contents/generations/tasks/" + id)
|
.url(volcBaseUrl + "/api/v3/contents/generations/tasks/" + id)
|
||||||
.header("Content-Type", "application/json")
|
.header("Content-Type", "application/json")
|
||||||
.header("Authorization", "Bearer " + apiKey)
|
.header("Authorization", "Bearer " + volcApiKey)
|
||||||
.get()
|
.get()
|
||||||
.build();
|
.build();
|
||||||
// 4. 发送同步请求(因方法需要返回值,使用execute而非enqueue)
|
|
||||||
Response response = OkHttpUtils.newCall(request).execute();
|
Response response = OkHttpUtils.newCall(request).execute();
|
||||||
// 5. 处理响应
|
|
||||||
if (!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
// 非200状态:返回错误信息(假设ByteBodyRes有error字段)
|
|
||||||
String errorMsg = response.body() != null ? response.body().string() : "uploadVideo error";
|
String errorMsg = response.body() != null ? response.body().string() : "uploadVideo error";
|
||||||
throw new Exception("uploadVideo error:" + errorMsg);
|
throw new Exception("uploadVideo error:" + errorMsg);
|
||||||
}
|
}
|
||||||
// 6. 解析成功响应为ByteBodyRes
|
|
||||||
if (response.body() == null) {
|
if (response.body() == null) {
|
||||||
throw new Exception("uploadVideo response null");
|
throw new Exception("uploadVideo response null");
|
||||||
}
|
}
|
||||||
|
|
||||||
String responseBody = response.body().string();
|
String responseBody = response.body().string();
|
||||||
return objectMapper.readValue(responseBody, ByteBodyRes.class);
|
return objectMapper.readValue(responseBody, ByteBodyRes.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AjaxResult cancelVideoTask(String id) throws Exception {
|
||||||
|
if (StringUtils.isBlank(id)) {
|
||||||
|
return AjaxResult.error("任务ID不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 向火山引擎发送 DELETE 请求取消任务
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(volcBaseUrl + "/api/v3/contents/generations/tasks/" + id)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.header("Authorization", "Bearer " + volcApiKey)
|
||||||
|
.delete()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Response response = OkHttpUtils.newCall(request).execute();
|
||||||
|
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
String errorMsg = response.body() != null ? response.body().string() : "cancel failed";
|
||||||
|
return AjaxResult.error("取消任务失败:" + errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return AjaxResult.success("任务已取消,余额已退回");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return AjaxResult.error("取消任务异常:" + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ SET FOREIGN_KEY_CHECKS = 0;
|
||||||
DROP TABLE IF EXISTS `ai_balance_change_record`;
|
DROP TABLE IF EXISTS `ai_balance_change_record`;
|
||||||
CREATE TABLE `ai_balance_change_record` (
|
CREATE TABLE `ai_balance_change_record` (
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`order_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '关联订单号',
|
||||||
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||||
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
|
@ -33,7 +34,8 @@ CREATE TABLE `ai_balance_change_record` (
|
||||||
`type` tinyint(1) NULL DEFAULT NULL COMMENT '操作类型',
|
`type` tinyint(1) NULL DEFAULT NULL COMMENT '操作类型',
|
||||||
`change_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '变更金额',
|
`change_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '变更金额',
|
||||||
`result_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '变更后金额',
|
`result_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '变更后金额',
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_order_no` (`order_no`) USING BTREE
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 1159 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '余额使用记录' ROW_FORMAT = DYNAMIC;
|
) ENGINE = InnoDB AUTO_INCREMENT = 1159 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '余额使用记录' ROW_FORMAT = DYNAMIC;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|
@ -1449,7 +1451,7 @@ CREATE TABLE `ai_manager` (
|
||||||
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者',
|
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者',
|
||||||
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
|
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
|
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'AI标题',
|
`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'AI标题',
|
||||||
`price` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '价格',
|
`price` decimal(10, 2) NULL DEFAULT 0.00 COMMENT '价格',
|
||||||
|
|
@ -1464,12 +1466,12 @@ CREATE TABLE `ai_manager` (
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Records of ai_manager
|
-- Records of ai_manager
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
INSERT INTO `ai_manager` VALUES (1, '0', 'admin', '2025-11-13 20:05:27', 'admin', '2025-12-23 14:30:07', NULL, '图生图1', 10.00, 0, '1girl, solo, exact same character as reference image, identical face eye color hairstyle accessories expression pose background lighting, (completely nude:1.2), naked, no clothes, breasts fully exposed, {胸部大小}, nipples perfectly matching skin tone, {动作}, pose that naturally conceals lower body from front view, legs positioned to avoid frontal genital exposure, side profile or back view emphasis, subtle natural body contours without explicit details, perfect anatomy, exactly two arms and two legs only, perfect hands with exactly 5 clearly separated fingers each no fusion no extra fingers, smooth natural skin texture, realistic proportions, masterpiece, best quality, ultra detailed, 8k, soft lighting, depth of field, high resolution, intricate details, cinematic composition, (if multiple characters: all characters following same rules no frontal exposure:1.1)(negative: clothes, bra, panties, underwear, bikini, swimsuit, any fabric even one pixel, censored, mosaic, bar censor, any censorship, pasties, nipple covers, frontal genital exposure, visible slit, visible pussy, exposed crotch, swollen labia, puffy labia, deformed genital area, dark mismatched crotch skin, any pubic details, extra arms, extra legs, extra hands, extra fingers, third arm, third leg, mutated limbs, more than two arms, more than two legs, fused fingers, deformed hands, bad hands, unnatural poses, violating human anatomy, loli, child, old, realistic photo, lowres:1.8, blurry, artifacts, overexposed, underexposed, pixelated, jpeg artifacts, watermark, text, signature, ugly, deformed, mutated, extra limbs, poorly drawn face, poorly drawn hands, missing limbs, floating limbs, disconnected limbs)', '11', '1,17');
|
INSERT INTO `ai_manager` VALUES (1, '0', 'admin', '2025-11-13 20:05:27', 'admin', '2025-12-23 14:30:07', NULL, '图生图', 10.00, 0, '1girl, solo, exact same character as reference image, (completely nude:1.2), naked, no clothes, breasts fully exposed, {胸部大小}, perfect anatomy, masterpiece, best quality', '11', NULL);
|
||||||
INSERT INTO `ai_manager` VALUES (2, '0', 'admin', '2025-11-21 22:24:28', 'admin', '2025-12-14 20:20:56', NULL, '图生图2', 10.00, 0, '生成{主题},{风格}包含{细节},分辨率{技术参数}的图像', '12', NULL);
|
INSERT INTO `ai_manager` VALUES (2, '0', 'admin', '2025-11-21 22:24:28', 'admin', '2025-12-14 20:20:56', NULL, '图生图-高级', 12.00, 0, '生成{主题},{风格}包含{细节},分辨率{技术参数}的图像', '12', NULL);
|
||||||
INSERT INTO `ai_manager` VALUES (3, '0', 'admin', '2025-11-13 20:06:02', 'admin', '2025-12-24 15:03:00', NULL, '一键换脸', 10.00, 1, '保持参考图1的内容风格不变,用参考图2的脸部对参考图1的脸部进行替换', '13', '');
|
INSERT INTO `ai_manager` VALUES (3, '0', 'admin', '2025-11-13 20:06:02', 'admin', '2025-12-24 15:03:00', NULL, '一键换脸', 10.00, 1, '保持参考图1的内容风格不变,用参考图2的脸部对参考图1的脸部进行替换', '13', NULL);
|
||||||
INSERT INTO `ai_manager` VALUES (4, '0', 'admin', '2025-11-13 20:07:33', 'admin', '2025-12-23 14:47:10', NULL, '快捷生图', 8.00, 0, '1girl, solo, detailed face with {发型} {眼睛颜色} {配饰} {表情} {姿势} in {背景}, {服装描述} {胸部大小} no pubic hair at all, no body hair anywhere from neck to toes, pose that naturally conceals lower body from front view, legs positioned to avoid frontal genital exposure, side profile or back view emphasis, subtle natural body contours without explicit details, perfect anatomy, exactly two arms and two legs only, perfect hands with exactly 5 clearly separated fingers each no fusion no extra fingers, smooth natural skin texture, realistic proportions, masterpiece, best quality, ultra detailed, 8k, soft lighting, depth of field, high resolution, intricate details, cinematic composition, (if multiple characters: {多人描述}, all characters following same rules no frontal exposure:1.1)(negative: everyday clothes, casual outfit, school uniform, regular dress, any non-specified clothing, clothing glitch, fabric clipping, pubic hair, body hair, happy trail, hair on abdomen, hair on stomach, hair on torso, hair around navel, any hair below neck except head hair, frontal genital exposure, visible slit, visible pussy, exposed crotch, swollen labia, puffy labia, deformed genital area, dark mismatched crotch skin, any pubic details, extra arms, extra legs, extra hands, extra fingers, third arm, third leg, mutated limbs, more than two arms, more than two legs, fused fingers, deformed hands, bad hands, unnatural poses, violating human anatomy, bad anatomy, loli, child, old, realistic photo, lowres:1.9, blurry, artifacts, overexposed, underexposed, pixelated, jpeg artifacts, watermark, text, signature, ugly, deformed, mutated, extra limbs, poorly drawn face, poorly drawn hands, missing limbs, floating limbs, disconnected limbs, clothes if nude mode, bra if nude mode, panties if nude mode, underwear if nude mode, bikini if nude mode, swimsuit if nude mode, any fabric even one pixel if nude mode, censored if nude mode, mosaic if nude mode, bar censor if nude mode, any censorship if nude mode, pasties if nude mode, nipple covers if nude mode)\n', '1', '8,5,11,64,66,68,70,72,74');
|
INSERT INTO `ai_manager` VALUES (4, '0', 'admin', '2025-11-13 20:07:33', 'admin', '2025-12-23 14:47:10', NULL, '快捷生图', 8.00, 0, '1girl, solo, detailed face with {发型} {眼睛颜色} {配饰} {表情} {姿势} in {背景}, {服装描述} {胸部大小}, perfect anatomy, masterpiece, best quality', '11', NULL);
|
||||||
INSERT INTO `ai_manager` VALUES (5, '0', 'admin', '2025-11-13 20:07:47', 'admin', '2026-01-08 14:58:37', '', '快捷生视频', 35.00, 0, '跳舞', '21', '');
|
INSERT INTO `ai_manager` VALUES (5, '0', 'admin', '2025-11-13 20:07:47', 'admin', '2026-01-08 14:58:37', NULL, '快捷生视频', 35.00, 0, '跳舞', '21', NULL);
|
||||||
INSERT INTO `ai_manager` VALUES (7, '0', 'admin', '2025-11-25 19:41:23', 'admin', '2025-11-25 19:41:23', NULL, '视频换脸', 35.00, 1, NULL, '22', NULL);
|
INSERT INTO `ai_manager` VALUES (7, '0', 'admin', '2025-11-25 19:41:23', 'admin', '2025-11-25 19:41:23', NULL, '视频换脸', 35.00, 1, '视频换脸功能', '22', NULL);
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
-- Table structure for ai_order
|
-- Table structure for ai_order
|
||||||
|
|
@ -1494,7 +1496,13 @@ CREATE TABLE `ai_order` (
|
||||||
`is_top` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'N' COMMENT '是否置顶:N-否 Y-是',
|
`is_top` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'N' COMMENT '是否置顶:N-否 Y-是',
|
||||||
`img1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '首帧图片',
|
`img1` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '首帧图片',
|
||||||
`img2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '第二张图片',
|
`img2` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '第二张图片',
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
`mode` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '生成模式:text-to-video 或 image-to-video',
|
||||||
|
`duration` int NULL DEFAULT 5 COMMENT '视频时长(秒)',
|
||||||
|
`resolution` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '720p' COMMENT '分辨率',
|
||||||
|
`ratio` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '9:16' COMMENT '宽高比',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_order_num` (`order_num`) USING BTREE,
|
||||||
|
KEY `idx_user_id` (`user_id`) USING BTREE
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 1310 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'API订单记录' ROW_FORMAT = DYNAMIC;
|
) ENGINE = InnoDB AUTO_INCREMENT = 1310 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'API订单记录' ROW_FORMAT = DYNAMIC;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|
@ -2792,6 +2800,7 @@ CREATE TABLE `ai_pay_setting` (
|
||||||
DROP TABLE IF EXISTS `ai_rebate_record`;
|
DROP TABLE IF EXISTS `ai_rebate_record`;
|
||||||
CREATE TABLE `ai_rebate_record` (
|
CREATE TABLE `ai_rebate_record` (
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`order_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '关联订单号',
|
||||||
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||||
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
|
@ -2801,7 +2810,8 @@ CREATE TABLE `ai_rebate_record` (
|
||||||
`superior_id` bigint NULL DEFAULT NULL COMMENT '上级ID',
|
`superior_id` bigint NULL DEFAULT NULL COMMENT '上级ID',
|
||||||
`subordinate_id` bigint NULL DEFAULT NULL COMMENT '下级ID',
|
`subordinate_id` bigint NULL DEFAULT NULL COMMENT '下级ID',
|
||||||
`amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '返佣金额',
|
`amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '返佣金额',
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_order_no` (`order_no`) USING BTREE
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 37 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '返佣记录' ROW_FORMAT = DYNAMIC;
|
) ENGINE = InnoDB AUTO_INCREMENT = 37 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '返佣记录' ROW_FORMAT = DYNAMIC;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|
@ -3103,6 +3113,7 @@ INSERT INTO `ai_sample_amount` VALUES (2, '0', 'admin', '2025-11-14 22:37:01', '
|
||||||
DROP TABLE IF EXISTS `ai_sample_amount_record`;
|
DROP TABLE IF EXISTS `ai_sample_amount_record`;
|
||||||
CREATE TABLE `ai_sample_amount_record` (
|
CREATE TABLE `ai_sample_amount_record` (
|
||||||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||||
|
`order_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '关联订单号',
|
||||||
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
|
||||||
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
|
@ -3113,7 +3124,8 @@ CREATE TABLE `ai_sample_amount_record` (
|
||||||
`sample_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '体验金额',
|
`sample_amount` decimal(10, 2) NULL DEFAULT NULL COMMENT '体验金额',
|
||||||
`recycle_time` datetime NULL DEFAULT NULL COMMENT '回收时间',
|
`recycle_time` datetime NULL DEFAULT NULL COMMENT '回收时间',
|
||||||
`status` tinyint NULL DEFAULT 0 COMMENT '回收状态:0-已发放 1-已回收',
|
`status` tinyint NULL DEFAULT 0 COMMENT '回收状态:0-已发放 1-已回收',
|
||||||
PRIMARY KEY (`id`) USING BTREE
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_order_no` (`order_no`) USING BTREE
|
||||||
) ENGINE = InnoDB AUTO_INCREMENT = 34 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '体验金领取记录' ROW_FORMAT = DYNAMIC;
|
) ENGINE = InnoDB AUTO_INCREMENT = 34 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '体验金领取记录' ROW_FORMAT = DYNAMIC;
|
||||||
|
|
||||||
-- ----------------------------
|
-- ----------------------------
|
||||||
|
|
@ -5813,4 +5825,36 @@ INSERT INTO `user_message` VALUES (2, 2);
|
||||||
INSERT INTO `user_message` VALUES (2, 3);
|
INSERT INTO `user_message` VALUES (2, 3);
|
||||||
INSERT INTO `user_message` VALUES (2, 4);
|
INSERT INTO `user_message` VALUES (2, 4);
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Table structure for ai_template
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ai_template`;
|
||||||
|
CREATE TABLE `ai_template` (
|
||||||
|
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '自增ID',
|
||||||
|
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模版名称',
|
||||||
|
`chinese_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '模版中文内容',
|
||||||
|
`english_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '模版英文内容',
|
||||||
|
`image_url` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '模版图片URL',
|
||||||
|
`ai_id` bigint NULL DEFAULT NULL COMMENT '关联AI类型ID',
|
||||||
|
`status` tinyint(1) NULL DEFAULT 1 COMMENT '状态(0禁用 1启用)',
|
||||||
|
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
|
||||||
|
`create_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '创建者',
|
||||||
|
`create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||||
|
`update_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '' COMMENT '更新者',
|
||||||
|
`update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||||
|
`del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)',
|
||||||
|
PRIMARY KEY (`id`) USING BTREE,
|
||||||
|
KEY `idx_ai_id` (`ai_id`) USING BTREE,
|
||||||
|
KEY `idx_status` (`status`) USING BTREE
|
||||||
|
) ENGINE = InnoDB AUTO_INCREMENT = 1001 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = 'AI模板表' ROW_FORMAT = DYNAMIC;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- Records of ai_template
|
||||||
|
-- ----------------------------
|
||||||
|
INSERT INTO `ai_template` (`name`, `chinese_content`, `english_content`, `image_url`, `ai_id`, `status`, `remark`) VALUES
|
||||||
|
('默认写真模板', '一个穿着衣服的年轻女性,微笑面对镜头,高清写真风格', 'A young woman wearing clothes, smiling at the camera, high-definition portrait style', 'https://seedance-1331490964.cos.ap-guangzhou.myqcloud.com/ai/default-template.jpg', 11, 1, '默认写真模板'),
|
||||||
|
('艺术裸体模板', '一个优雅的艺术裸体女性,柔和光线,专业摄影风格', 'An elegant artistic nude female with soft lighting, professional photography style', 'https://seedance-1331490964.cos.ap-guangzhou.myqcloud.com/ai/nude-art.jpg', 11, 1, '艺术裸体模板'),
|
||||||
|
('时尚都市模板', '时尚都市年轻女性写真,现代潮流风格', 'Fashionable urban young woman portrait, modern trendy style', 'https://seedance-1331490964.cos.ap-guangzhou.myqcloud.com/ai/fashion.jpg', 21, 1, '时尚写真模板'),
|
||||||
|
('性感写真模板', '性感迷人女性写真,专业灯光和构图', 'Sexy and charming female portrait with professional lighting and composition', 'https://seedance-1331490964.cos.ap-guangzhou.myqcloud.com/ai/sexy.jpg', 11, 1, '性感写真模板');
|
||||||
|
|
||||||
SET FOREIGN_KEY_CHECKS = 1;
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue