Compare commits

...

3 Commits

Author SHA1 Message Date
yys c04c1e572b Merge remote-tracking branch 'origin/seedance' into seedance 2026-04-01 13:28:25 +08:00
yys f9c12bb1e0 feat: 火山素材组、素材管理 2026-03-31 18:32:10 +08:00
yys a04bd71afc fix: 修改路径错误 2026-03-31 17:56:37 +08:00
29 changed files with 1049 additions and 0 deletions

View File

@ -0,0 +1,101 @@
package com.ruoyi.api;
import com.ruoyi.ai.service.IByteAssetService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.request.asset.DeleteAssetRequest;
import com.ruoyi.common.core.request.asset.GetAssetRequest;
import com.ruoyi.common.core.request.asset.ListAssetsRequest;
import com.ruoyi.common.core.request.asset.UpdateAssetRequest;
import com.ruoyi.common.core.response.asset.CreateAssetResponse;
import com.ruoyi.common.core.response.asset.GetAssetResponse;
import com.ruoyi.common.core.response.asset.ListAssetsResponse;
import com.ruoyi.common.core.response.asset.UpdateAssetResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
/**
* 火山 - 素材管理api.docx Assets APICreateAsset 先上传存储桶再调三方接口
*/
@Slf4j
@RestController
@RequestMapping("/api/byteAsset")
@Api(tags = "火山 - 素材管理")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ByteAssetApiController extends BaseController {
private final IByteAssetService byteAssetService;
@PostMapping(value = "/createAsset", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@ApiOperation("CreateAsset先将文件上传至对象存储再调用 CreateAsset")
public AjaxResult<CreateAssetResponse> createAsset(
@ApiParam(value = "素材文件", required = true) @RequestPart("file") MultipartFile file,
@ApiParam(value = "所属素材组 IdGroupId", required = true) @RequestParam("groupId") String groupId,
@ApiParam(value = "素材类型Image / Video / Audio", required = true) @RequestParam("assetType") String assetType,
@ApiParam(value = "素材名称,可选") @RequestParam(value = "name", required = false) String name,
@ApiParam(value = "项目名称,可选,默认 default") @RequestParam(value = "projectName", required = false) String projectName) {
try {
return AjaxResult.success(byteAssetService.createAsset(file, groupId, assetType, name, projectName));
} catch (Exception e) {
log.error("创建素材时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
@PostMapping("/listAssets")
@ApiOperation("ListAssets查询素材列表")
public AjaxResult<ListAssetsResponse> listAssets(@RequestBody ListAssetsRequest request) {
try {
return AjaxResult.success(byteAssetService.listAssets(request));
} catch (Exception e) {
log.error("查询素材列表时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
@PostMapping("/getAsset")
@ApiOperation("GetAsset查询单个素材")
public AjaxResult<GetAssetResponse> getAsset(@RequestBody GetAssetRequest request) {
try {
return AjaxResult.success(byteAssetService.getAsset(request));
} catch (Exception e) {
log.error("查询素材详情时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
@PostMapping("/updateAsset")
@ApiOperation("UpdateAsset更新素材当前仅名称")
public AjaxResult<UpdateAssetResponse> updateAsset(@RequestBody UpdateAssetRequest request) {
try {
return AjaxResult.success(byteAssetService.updateAsset(request));
} catch (Exception e) {
log.error("更新素材时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
@PostMapping("/deleteAsset")
@ApiOperation("DeleteAsset删除素材")
public AjaxResult<Void> deleteAsset(@RequestBody DeleteAssetRequest request) {
try {
byteAssetService.deleteAsset(request);
return AjaxResult.success();
} catch (Exception e) {
log.error("删除素材时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,79 @@
package com.ruoyi.api;
import com.ruoyi.ai.service.IByteAssetGroupService;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.request.asset.CreateAssetGroupRequest;
import com.ruoyi.common.core.request.asset.GetAssetGroupRequest;
import com.ruoyi.common.core.request.asset.ListAssetsGroupRequest;
import com.ruoyi.common.core.request.asset.UpdateAssetGroupRequest;
import com.ruoyi.common.core.response.asset.CreateAssetGroupResponse;
import com.ruoyi.common.core.response.asset.GetAssetGroupResponse;
import com.ruoyi.common.core.response.asset.ListAssetsGroupResponse;
import com.ruoyi.common.core.response.asset.UpdateAssetGroupResponse;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 火山 - 素材组管理 Controller
*/
@Slf4j
@RestController
@RequestMapping("/api/byteAssetGroup")
@Api(tags = "火山 - 素材组管理")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ByteAssetGroupApiController extends BaseController {
private final IByteAssetGroupService groupService;
@PostMapping("/listAssetGroups")
@ApiOperation("ListAssetGroups查询素材资产组合列表")
public AjaxResult<ListAssetsGroupResponse> listAssetGroups(@RequestBody ListAssetsGroupRequest request) {
try {
return AjaxResult.success(groupService.listAssetGroups(request));
} catch (Exception e) {
log.error("查询素材组列表时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
@PostMapping("/createAssetGroup")
@ApiOperation("CreateAssetGroup创建素材资产组合")
public AjaxResult<CreateAssetGroupResponse> createAssetGroup(@RequestBody CreateAssetGroupRequest request) {
try {
return AjaxResult.success(groupService.createAssetGroup(request));
} catch (Exception e) {
log.error("创建素材组时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
@PostMapping("/getAssetGroup")
@ApiOperation("GetAssetGroup查询单个素材资产组合")
public AjaxResult<GetAssetGroupResponse> getAssetGroup(@RequestBody GetAssetGroupRequest request) {
try {
return AjaxResult.success(groupService.getAssetGroup(request));
} catch (Exception e) {
log.error("查询素材组详情时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
@PostMapping("/updateAssetGroup")
@ApiOperation("UpdateAssetGroup更新素材资产组合")
public AjaxResult<UpdateAssetGroupResponse> updateAssetGroup(@RequestBody UpdateAssetGroupRequest request) {
try {
return AjaxResult.success(groupService.updateAssetGroup(request));
} catch (Exception e) {
log.error("更新素材组时发生异常", e);
return AjaxResult.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,28 @@
package com.ruoyi.common.core.request.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* CreateAssetGroup POST /open/CreateAssetGroupapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "创建 Asset Group素材资产组合。首次创建需在控制台签署授权函。")
public class CreateAssetGroupRequest {
@ApiModelProperty(value = "Asset Group素材资产组合的名称上限为 64 字符。", required = true)
private String name;
@ApiModelProperty(value = "Asset Group素材资产组合的描述上限为 300 字符。")
private String description;
@ApiModelProperty(value = "Asset Group素材资产组合的类型。可选值AIGC虚拟人像。当前仅支持 AIGC 类型。")
private String groupType;
@ApiModelProperty(value = "资源所属的项目名称,默认值为 default。若资源不在默认项目中需填写正确的项目名称。")
private String projectName;
}

View File

@ -0,0 +1,33 @@
package com.ruoyi.common.core.request.asset;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* CreateAsset POST /open/CreateAsset 请求体api.docx由服务端在上传存储桶后组装 URL
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "CreateAsset 第三方接口请求体")
public class CreateAssetOpenApiRequest {
@ApiModelProperty(value = "Asset素材资产所属的 Asset Group素材资产组合的 Id。", required = true)
private String groupId;
@JsonProperty("URL")
@ApiModelProperty(value = "传入的 Asset素材资产的公共可访问地址。", required = true)
private String url;
@ApiModelProperty(value = "Asset素材资产的名称上限为 64 个字符。仅用于 ListAssets 模糊搜索,不参与模型推理。")
private String name;
@ApiModelProperty(value = "Asset素材资产的类型。可选值Image、Video、Audio。", required = true)
private String assetType;
@ApiModelProperty(value = "资源所属的项目名称,默认 default。需与所属 Asset Group 的 ProjectName 一致。")
private String projectName;
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.common.core.request.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* DeleteAsset POST /open/DeleteAssetapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "删除单个 Asset素材资产")
public class DeleteAssetRequest {
@ApiModelProperty(value = "需要删除的 Asset素材资产的 Id。", required = true)
private String id;
@ApiModelProperty(value = "需要删除的 Asset素材资产所属的项目名称默认 default。")
private String projectName;
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.common.core.request.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* GetAssetGroup POST /open/GetAssetGroupapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "获取单个 Asset Group素材资产组合信息")
public class GetAssetGroupRequest {
@ApiModelProperty(value = "Asset Group素材资产组合的 Id。", required = true)
private String id;
@ApiModelProperty(value = "需要查询的 Asset Group素材资产组合所属的项目名称默认值为 default。若资源不在默认项目中需填写正确的项目名称。")
private String projectName;
}

View File

@ -0,0 +1,22 @@
package com.ruoyi.common.core.request.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* GetAsset POST /open/GetAssetapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "获取单个 Asset素材资产信息")
public class GetAssetRequest {
@ApiModelProperty(value = "Asset素材资产的 Id。", required = true)
private String id;
@ApiModelProperty(value = "需要查询的 Asset 所属的项目名称,默认 default。")
private String projectName;
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.common.core.request.asset;
import com.ruoyi.common.core.request.asset.dto.ListAssetsGroupFilter;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* ListAssetGroups POST /open/ListAssetGroupsapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "查询符合筛选条件的 Asset Groups素材资产组合列表")
public class ListAssetsGroupRequest {
@ApiModelProperty(value = "搜索的过滤条件。", required = true)
private ListAssetsGroupFilter filter;
@ApiModelProperty(value = "搜索页码,可用于列表分页功能,从 1 开始。", required = true)
private int pageNumber;
@ApiModelProperty(value = "每页搜索结果的数量,上限为 100。", required = true)
private int pageSize;
@ApiModelProperty(value = "用于排序的字段名称,默认值 createTime。支持CreateTime创建时间、UpdateTime更新时间")
private String sortBy;
@ApiModelProperty(value = "排序顺序,默认值 Desc。可选值Desc降序、Asc升序")
private String sortOrder;
@ApiModelProperty(value = "资源所属的项目名称,默认值为 default。若资源不在默认项目中需填写正确的项目名称。")
private String projectName;
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.common.core.request.asset;
import com.ruoyi.common.core.request.asset.dto.ListAssetsFilter;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* ListAssets POST /open/ListAssetsapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "查询符合筛选条件的 Assets素材资产列表")
public class ListAssetsRequest {
@ApiModelProperty(value = "搜索的过滤条件。", required = true)
private ListAssetsFilter filter;
@ApiModelProperty(value = "搜索页码,从 1 开始。", required = true)
private int pageNumber;
@ApiModelProperty(value = "每页搜索结果的数量,上限为 100。", required = true)
private int pageSize;
@ApiModelProperty(value = "排序字段,默认 createTime。支持CreateTime、UpdateTime、GroupId。")
private String sortBy;
@ApiModelProperty(value = "排序顺序,默认 Desc。可选Desc、Asc。")
private String sortOrder;
@ApiModelProperty(value = "资源所属的项目名称,默认 default。")
private String projectName;
}

View File

@ -0,0 +1,28 @@
package com.ruoyi.common.core.request.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* UpdateAssetGroup POST /open/UpdateAssetGroupapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "更新单个 Asset Group素材资产组合信息。当前仅支持更新 Name 和 Description。")
public class UpdateAssetGroupRequest {
@ApiModelProperty(value = "需要更新的 Asset Group素材资产组合的 Id。", required = true)
private String id;
@ApiModelProperty(value = "需要更新的 Asset Group素材资产组合的新名称上限为 64 个字符。")
private String name;
@ApiModelProperty(value = "需要更新的 Asset Group素材资产组合的新描述上限为 300 字符。")
private String description;
@ApiModelProperty(value = "需要更新的 Asset Group素材资产组合所属的项目名称默认值为 default。若资源不在默认项目中需填写正确的项目名称。")
private String projectName;
}

View File

@ -0,0 +1,25 @@
package com.ruoyi.common.core.request.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* UpdateAsset POST /open/UpdateAssetapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "更新单个 Asset素材资产信息当前仅支持更新 Name。")
public class UpdateAssetRequest {
@ApiModelProperty(value = "需要更新的 Asset素材资产的 Id。", required = true)
private String id;
@ApiModelProperty(value = "需要更新的 Asset素材资产的新名称上限为 64 个字符。")
private String name;
@ApiModelProperty(value = "需要更新的 Asset素材资产所属的项目名称默认 default。")
private String projectName;
}

View File

@ -0,0 +1,30 @@
package com.ruoyi.common.core.request.asset.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* ListAssets 请求中的 Filterapi.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "ListAssets 过滤条件")
public class ListAssetsFilter {
@ApiModelProperty(value = "Asset素材资产所属的 Asset Group素材资产组合的 Id 列表。")
private List<String> groupIds;
@ApiModelProperty(value = "Asset Group素材资产组合的类型。可选值AIGC虚拟人像。", required = true)
private String groupType;
@ApiModelProperty(value = "任务状态列表Active已处理完毕、Processing预处理中、Failed处理失败")
private List<String> statuses;
@ApiModelProperty(value = "Asset素材资产的名称上限为 64 个字符(模糊搜索)。")
private String name;
}

View File

@ -0,0 +1,27 @@
package com.ruoyi.common.core.request.asset.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* ListAssetGroups 请求中的 Filter 对象api.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "ListAssetGroups 过滤条件")
public class ListAssetsGroupFilter {
@ApiModelProperty(value = "Asset Group素材资产组合的名称上限为 64 个字符(模糊搜索)。")
private String name;
@ApiModelProperty(value = "Asset素材资产所属的 Asset Group素材资产组合的 Id 列表。")
private List<String> groupIds;
@ApiModelProperty(value = "Asset Group素材资产组合的类型。可选值AIGC虚拟人像。", required = true)
private String groupType;
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.common.core.response.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "CreateAssetGroup 返回参数")
public class CreateAssetGroupResponse {
@ApiModelProperty(value = "Asset Group素材资产组合的 Id。")
private String id;
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.common.core.response.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "CreateAsset 返回参数")
public class CreateAssetResponse {
@ApiModelProperty(value = "Asset素材资产的 Id。")
private String id;
}

View File

@ -0,0 +1,37 @@
package com.ruoyi.common.core.response.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "GetAssetGroup 返回参数")
public class GetAssetGroupResponse {
@ApiModelProperty(value = "Asset Group素材资产组合的 Id。")
private String id;
@ApiModelProperty(value = "Asset Group素材资产组合的名称上限为 64 个字符。")
private String name;
@ApiModelProperty(value = "Asset Group素材资产组合的标题。已废弃请直接使用参数 Name。")
private String title;
@ApiModelProperty(value = "Asset Group素材资产组合的描述上限为 300 字符。")
private String description;
@ApiModelProperty(value = "Asset Group素材资产组合的类型。AIGC虚拟人像。")
private String groupType;
@ApiModelProperty(value = "资源所属的项目名称。")
private String projectName;
@ApiModelProperty(value = "创建时间。")
private String createTime;
@ApiModelProperty(value = "更新时间。")
private String updateTime;
}

View File

@ -0,0 +1,46 @@
package com.ruoyi.common.core.response.asset;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.ruoyi.common.core.response.asset.dto.AssetError;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "GetAsset 返回参数")
public class GetAssetResponse {
@ApiModelProperty(value = "Asset素材资产的 Id。")
private String id;
@ApiModelProperty(value = "Asset素材资产的名称上限为 64 个字符。")
private String name;
@JsonProperty("URL")
@ApiModelProperty(value = "Asset素材资产的访问地址。有效期为 12 小时,请及时保存。")
private String url;
@ApiModelProperty(value = "Asset素材资产的类型Image、Video、Audio。")
private String assetType;
@ApiModelProperty(value = "Asset素材资产所属的 Asset Group素材资产组合的 Id。")
private String groupId;
@ApiModelProperty(value = "任务状态Active、Processing、Failed。")
private String status;
@ApiModelProperty(value = "错误信息。")
private AssetError error;
@ApiModelProperty(value = "创建时间。")
private String createTime;
@ApiModelProperty(value = "更新时间。")
private String updateTime;
@ApiModelProperty(value = "资源所属的项目名称。")
private String projectName;
}

View File

@ -0,0 +1,28 @@
package com.ruoyi.common.core.response.asset;
import com.ruoyi.common.core.response.asset.dto.ListAssetsGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "ListAssetGroups 返回参数")
public class ListAssetsGroupResponse {
@ApiModelProperty(value = "返回的 Asset Group素材资产组合的总数。")
private int totalCount;
@ApiModelProperty(value = "返回的页数。")
private int pageNumber;
@ApiModelProperty(value = "每页搜索结果的数量,上限为 100。")
private int pageSize;
@ApiModelProperty(value = "符合筛选条件的 Asset Group素材资产组合数组。")
private List<ListAssetsGroup> items;
}

View File

@ -0,0 +1,28 @@
package com.ruoyi.common.core.response.asset;
import com.ruoyi.common.core.response.asset.dto.ListAssetItem;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "ListAssets 返回参数")
public class ListAssetsResponse {
@ApiModelProperty(value = "符合筛选条件的 Asset 数组。")
private List<ListAssetItem> items;
@ApiModelProperty(value = "返回总数。")
private int totalCount;
@ApiModelProperty(value = "返回的页数。")
private int pageNumber;
@ApiModelProperty(value = "每页搜索结果的数量,上限为 100。")
private int pageSize;
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.common.core.response.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "UpdateAssetGroup 返回参数")
public class UpdateAssetGroupResponse {
@ApiModelProperty(value = "Asset Group素材资产组合的 Id。")
private String id;
}

View File

@ -0,0 +1,16 @@
package com.ruoyi.common.core.response.asset;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "UpdateAsset 返回参数")
public class UpdateAssetResponse {
@ApiModelProperty(value = "Asset素材资产的 Id。")
private String id;
}

View File

@ -0,0 +1,19 @@
package com.ruoyi.common.core.response.asset.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "素材处理错误信息")
public class AssetError {
@ApiModelProperty(value = "错误码。")
private String code;
@ApiModelProperty(value = "错误信息。")
private String message;
}

View File

@ -0,0 +1,47 @@
package com.ruoyi.common.core.response.asset.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* ListAssets 返回 Items 元素api.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "素材资产(列表项)")
public class ListAssetItem {
@ApiModelProperty(value = "Asset素材资产的 Id。")
private String id;
@ApiModelProperty(value = "Asset素材资产的名称上限为 64 个字符。")
private String name;
@ApiModelProperty(value = "Asset素材资产的公共可访问地址。有效期为 12 小时,请及时保存。")
private String url;
@ApiModelProperty(value = "Asset素材资产所属的 Asset Group素材资产组合的 Id。")
private String groupId;
@ApiModelProperty(value = "Asset素材资产的类型Image、Video、Audio。")
private String assetType;
@ApiModelProperty(value = "任务状态Active、Processing、Failed。")
private String status;
@ApiModelProperty(value = "错误信息(处理失败时)。")
private AssetError error;
@ApiModelProperty(value = "资源所属的项目名称。")
private String projectName;
@ApiModelProperty(value = "创建时间。")
private String createTime;
@ApiModelProperty(value = "更新时间。")
private String updateTime;
}

View File

@ -0,0 +1,40 @@
package com.ruoyi.common.core.response.asset.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* ListAssetGroups 返回 Items 元素api.docx
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel(description = "素材资产组合(列表项)")
public class ListAssetsGroup {
@ApiModelProperty(value = "Asset Group素材资产组合的 Id。")
private String id;
@ApiModelProperty(value = "Asset Group素材资产组合的名称上限为 64 个字符。")
private String name;
@ApiModelProperty(value = "Asset Group素材资产组合的标题。已废弃请直接使用参数 Name。")
private String title;
@ApiModelProperty(value = "Asset Group素材资产组合的描述上限为 300 字符。")
private String description;
@ApiModelProperty(value = "Asset Group素材资产组合的类型。AIGC虚拟人像。")
private String groupType;
@ApiModelProperty(value = "资源所属的项目名称。")
private String projectName;
@ApiModelProperty(value = "创建时间。")
private String createTime;
@ApiModelProperty(value = "更新时间。")
private String updateTime;
}

View File

@ -0,0 +1,23 @@
package com.ruoyi.ai.service;
import com.ruoyi.common.core.request.asset.CreateAssetGroupRequest;
import com.ruoyi.common.core.request.asset.GetAssetGroupRequest;
import com.ruoyi.common.core.request.asset.ListAssetsGroupRequest;
import com.ruoyi.common.core.request.asset.UpdateAssetGroupRequest;
import com.ruoyi.common.core.response.asset.CreateAssetGroupResponse;
import com.ruoyi.common.core.response.asset.GetAssetGroupResponse;
import com.ruoyi.common.core.response.asset.ListAssetsGroupResponse;
import com.ruoyi.common.core.response.asset.UpdateAssetGroupResponse;
import java.io.IOException;
public interface IByteAssetGroupService {
ListAssetsGroupResponse listAssetGroups(ListAssetsGroupRequest request) throws IOException;
CreateAssetGroupResponse createAssetGroup(CreateAssetGroupRequest request) throws IOException;
GetAssetGroupResponse getAssetGroup(GetAssetGroupRequest request) throws IOException;
UpdateAssetGroupResponse updateAssetGroup(UpdateAssetGroupRequest request) throws IOException;
}

View File

@ -0,0 +1,29 @@
package com.ruoyi.ai.service;
import com.ruoyi.common.core.request.asset.DeleteAssetRequest;
import com.ruoyi.common.core.request.asset.GetAssetRequest;
import com.ruoyi.common.core.request.asset.ListAssetsRequest;
import com.ruoyi.common.core.request.asset.UpdateAssetRequest;
import com.ruoyi.common.core.response.asset.CreateAssetResponse;
import com.ruoyi.common.core.response.asset.GetAssetResponse;
import com.ruoyi.common.core.response.asset.ListAssetsResponse;
import com.ruoyi.common.core.response.asset.UpdateAssetResponse;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
public interface IByteAssetService {
/**
* 先将文件上传至对象存储得到公网 URL再调用 CreateAsset
*/
CreateAssetResponse createAsset(MultipartFile file, String groupId, String assetType, String name, String projectName) throws Exception;
ListAssetsResponse listAssets(ListAssetsRequest request) throws IOException;
GetAssetResponse getAsset(GetAssetRequest request) throws IOException;
UpdateAssetResponse updateAsset(UpdateAssetRequest request) throws IOException;
void deleteAsset(DeleteAssetRequest request) throws IOException;
}

View File

@ -0,0 +1,88 @@
package com.ruoyi.ai.service.impl;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.ruoyi.common.utils.http.OkHttpUtils;
import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class BaseByteApiService {
protected final ObjectMapper objectMapper = new ObjectMapper()
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.setPropertyNamingStrategy(PropertyNamingStrategies.UPPER_CAMEL_CASE)
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
// API地址可配置在配置文件中
@Value("${byteapi.url}")
protected String API_URL;
@Value("${byteapi.apiKey}")
protected String apiKey;
/**
* POST JSON 调用方舟 OpenAPI若响应含 {@code Result} 节点则解析为业务对象 api.docx 返回示例一致
*/
protected <T> T httpExecute(String path, Object request, Class<T> clz) throws IOException {
String jsonBody = objectMapper.writeValueAsString(request);
RequestBody body = RequestBody.create(
MediaType.parse("application/json; charset=utf-8"),
jsonBody);
Request httpRequest = new Request.Builder()
.url(API_URL + path)
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiKey)
.post(body)
.build();
try (Response response = OkHttpUtils.newCall(httpRequest).execute()) {
if (!response.isSuccessful()) {
String errorMsg = response.body() != null ? response.body().string() : "execute error";
throw new RuntimeException("execute error" + errorMsg);
}
if (response.body() == null) {
throw new RuntimeException("response body null");
}
String responseBody = response.body().string();
JsonNode root = objectMapper.readTree(responseBody);
JsonNode result = root.get("Result");
if (result != null && !result.isNull()) {
return objectMapper.treeToValue(result, clz);
}
return objectMapper.readValue(responseBody, clz);
}
}
/**
* 无业务体返回的 OpenAPI 调用 DeleteAsset
*/
protected void httpExecuteNoContent(String path, Object request) throws IOException {
String jsonBody = objectMapper.writeValueAsString(request);
RequestBody body = RequestBody.create(
MediaType.parse("application/json; charset=utf-8"),
jsonBody);
Request httpRequest = new Request.Builder()
.url(API_URL + path)
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiKey)
.post(body)
.build();
try (Response response = OkHttpUtils.newCall(httpRequest).execute()) {
if (!response.isSuccessful()) {
String errorMsg = response.body() != null ? response.body().string() : "execute error";
throw new RuntimeException("execute error" + errorMsg);
}
}
}
}

View File

@ -0,0 +1,43 @@
package com.ruoyi.ai.service.impl;
import com.ruoyi.ai.service.IByteAssetGroupService;
import com.ruoyi.common.core.request.asset.CreateAssetGroupRequest;
import com.ruoyi.common.core.request.asset.GetAssetGroupRequest;
import com.ruoyi.common.core.request.asset.ListAssetsGroupRequest;
import com.ruoyi.common.core.request.asset.UpdateAssetGroupRequest;
import com.ruoyi.common.core.response.asset.CreateAssetGroupResponse;
import com.ruoyi.common.core.response.asset.GetAssetGroupResponse;
import com.ruoyi.common.core.response.asset.ListAssetsGroupResponse;
import com.ruoyi.common.core.response.asset.UpdateAssetGroupResponse;
import org.springframework.stereotype.Service;
import java.io.IOException;
@Service
public class ByteAssetGroupService extends BaseByteApiService implements IByteAssetGroupService {
private static final String LIST_ASSET_GROUPS_URL = "/open/ListAssetGroups";
private static final String CREATE_ASSET_GROUP_URL = "/open/CreateAssetGroup";
private static final String GET_ASSET_GROUP_URL = "/open/GetAssetGroup";
private static final String UPDATE_ASSET_GROUP_URL = "/open/UpdateAssetGroup";
@Override
public ListAssetsGroupResponse listAssetGroups(ListAssetsGroupRequest request) throws IOException {
return httpExecute(LIST_ASSET_GROUPS_URL, request, ListAssetsGroupResponse.class);
}
@Override
public CreateAssetGroupResponse createAssetGroup(CreateAssetGroupRequest request) throws IOException {
return httpExecute(CREATE_ASSET_GROUP_URL, request, CreateAssetGroupResponse.class);
}
@Override
public GetAssetGroupResponse getAssetGroup(GetAssetGroupRequest request) throws IOException {
return httpExecute(GET_ASSET_GROUP_URL, request, GetAssetGroupResponse.class);
}
@Override
public UpdateAssetGroupResponse updateAssetGroup(UpdateAssetGroupRequest request) throws IOException {
return httpExecute(UPDATE_ASSET_GROUP_URL, request, UpdateAssetGroupResponse.class);
}
}

View File

@ -0,0 +1,70 @@
package com.ruoyi.ai.service.impl;
import com.ruoyi.ai.service.IByteAssetService;
import com.ruoyi.common.core.request.asset.CreateAssetOpenApiRequest;
import com.ruoyi.common.core.request.asset.DeleteAssetRequest;
import com.ruoyi.common.core.request.asset.GetAssetRequest;
import com.ruoyi.common.core.request.asset.ListAssetsRequest;
import com.ruoyi.common.core.request.asset.UpdateAssetRequest;
import com.ruoyi.common.core.response.asset.CreateAssetResponse;
import com.ruoyi.common.core.response.asset.GetAssetResponse;
import com.ruoyi.common.core.response.asset.ListAssetsResponse;
import com.ruoyi.common.core.response.asset.UpdateAssetResponse;
import com.ruoyi.common.utils.AwsS3Util;
import com.ruoyi.common.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@Service
@RequiredArgsConstructor
public class ByteAssetService extends BaseByteApiService implements IByteAssetService {
private final AwsS3Util awsS3Util;
private static final String CREATE_ASSET_URL = "/open/CreateAsset";
private static final String LIST_ASSETS_URL = "/open/ListAssets";
private static final String GET_ASSET_URL = "/open/GetAsset";
private static final String UPDATE_ASSET_URL = "/open/UpdateAsset";
private static final String DELETE_ASSET_URL = "/open/DeleteAsset";
@Override
public CreateAssetResponse createAsset(MultipartFile file, String groupId, String assetType, String name, String projectName) throws Exception {
if (file == null || file.isEmpty()) {
throw new IllegalArgumentException("上传文件不能为空");
}
if (StringUtils.isBlank(groupId) || StringUtils.isBlank(assetType)) {
throw new IllegalArgumentException("groupId、assetType 不能为空");
}
String publicUrl = awsS3Util.uploadMultipartFile(file, true);
CreateAssetOpenApiRequest body = new CreateAssetOpenApiRequest();
body.setGroupId(groupId);
body.setUrl(publicUrl);
body.setName(name);
body.setAssetType(assetType);
body.setProjectName(projectName);
return httpExecute(CREATE_ASSET_URL, body, CreateAssetResponse.class);
}
@Override
public ListAssetsResponse listAssets(ListAssetsRequest request) throws IOException {
return httpExecute(LIST_ASSETS_URL, request, ListAssetsResponse.class);
}
@Override
public GetAssetResponse getAsset(GetAssetRequest request) throws IOException {
return httpExecute(GET_ASSET_URL, request, GetAssetResponse.class);
}
@Override
public UpdateAssetResponse updateAsset(UpdateAssetRequest request) throws IOException {
return httpExecute(UPDATE_ASSET_URL, request, UpdateAssetResponse.class);
}
@Override
public void deleteAsset(DeleteAssetRequest request) throws IOException {
httpExecuteNoContent(DELETE_ASSET_URL, request);
}
}