Commit 77fc37db by lijinqi

1.模型接口转发 代码迁移

2.report模块 注释
parent 57e10489
package com.luhu.computility.framework.common;
/**
* @version 1.0
* @Author ljq
* @Date 2025/4/23
* @注释
*/
public interface CustomizerHttpHeaders {
public static final String APPID = "appId";
public static final String TIMESTAMP = "timestamp";
public static final String NONCE = "nonce";
public static final String SIGN = "sign";
}
package com.luhu.computility.framework.common.exception.enums;
import com.luhu.computility.framework.common.exception.ErrorCode;
/**
* 全局错误码枚举
* 0-999 系统异常编码保留
*
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
* 虽然说,HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
*
* @author 芋道源码
*/
public interface GlobalResponseCodeConstants {
ErrorCode SUCCESS = new ErrorCode(0, "成功");
ErrorCode EXTERNAL_SUCCESS = new ErrorCode(200, "请求成功");
// ========== 客户端错误段 ==========
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到");
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
ErrorCode REQUEST_TIMEOUT = new ErrorCode(408, "请求超时");
ErrorCode PAYLOAD_TOO_LARGE = new ErrorCode(413, "请求体过大");
ErrorCode URI_TOO_LONG = new ErrorCode(414, "请求 URI 过长");
ErrorCode UNSUPPORTED_MEDIA_TYPE = new ErrorCode(415, "不支持的媒体类型");
ErrorCode UNPROCESSABLE_ENTITY = new ErrorCode(422, "请求无法处理");
// ========== 服务端错误段 ==========
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
ErrorCode TIME_OUT_ERROR = new ErrorCode(408, "请求超时");
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "错误的配置项");
ErrorCode BAD_GATEWAY = new ErrorCode(502, "网关错误");
ErrorCode SERVICE_UNAVAILABLE = new ErrorCode(503, "服务不可用");
ErrorCode GATEWAY_TIMEOUT = new ErrorCode(504, "网关超时");
ErrorCode HTTP_VERSION_NOT_SUPPORTED = new ErrorCode(505, "不支持的 HTTP 版本");
// ========== 自定义错误段 ==========
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
ErrorCode IMAGE_EXCEPTION = new ErrorCode(998, "图片文件或地址必须上传一个");
ErrorCode SOURCEIMAGE_IMAGE_EXCEPTION = new ErrorCode(996, "原始图片文件或地址必传一个且仅能传一个。二选一");
ErrorCode TARGETIMAGE_IMAGE_EXCEPTION = new ErrorCode(995, "模板图片文件或地址必传一个且仅能传一个。二选一");
ErrorCode IMAGE_UNIQUE = new ErrorCode(994, "图片文件或地址只能上传一个");
ErrorCode INVALID_SERIAL_NUMBER = new ErrorCode(993, "无效的流水号");
ErrorCode BEING_GENERATED = new ErrorCode(992, "还在生成中...");
}
......@@ -174,4 +174,54 @@ public class HttpUtils {
}
}
public static String postIncludeImage(String url, Map<String, String> headers, Map<String, Object> formMaps) {
try (HttpResponse response = openApiPost(url)
.addHeaders(headers)
.form(formMaps)
//.form(fileName, file) // 上传文件,"fileName"是接口中定义的字段名
.execute()) {
return response.body();
}
}
public static HttpRequest openApiPost(String url) {
return HttpRequest.post(url)
.setReadTimeout(300000);
}
public static String get(String url, Map<String, String> headers, Map<String, String> queryParams) {
try {
// 构建查询参数字符串
StringBuilder queryBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
if (queryBuilder.length() > 0) {
queryBuilder.append("&");
}
queryBuilder.append(entry.getKey())
.append("=")
.append(entry.getValue());
}
// 拼接完整的 URL
String fullUrl = url;
if (queryBuilder.length() > 0) {
fullUrl += "?" + queryBuilder.toString();
}
// 发送 GET 请求并返回响应体
try (HttpResponse response = HttpRequest.get(fullUrl)
.addHeaders(headers)
.execute()) {
return response.body();
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
......@@ -28,6 +28,10 @@ public abstract class AuthorizeRequestsCustomizer
return webProperties.getAppApi().getPrefix() + url;
}
protected String buildOpenApi(String url) {
return webProperties.getOpenApi().getPrefix() + url;
}
@Override
public int getOrder() {
return 0;
......
package com.luhu.computility.framework.swagger.config;
import com.luhu.computility.framework.common.CustomizerHttpHeaders;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
......@@ -152,5 +153,36 @@ public class ComputilitySwaggerAutoConfiguration {
.schema(new StringSchema()._default("Bearer test1").name(HEADER_TENANT_ID).description("认证 Token")); // 默认:使用用户编号为 1
}
public static GroupedOpenApi buildGroupedOpenApiAuthBySign(String group) {
return GroupedOpenApi.builder()
.group(group)
.pathsToMatch( "/open-api/" + group + "/**")
.addOperationCustomizer((operation, handlerMethod) -> operation
.addParametersItem(new Parameter()
.name(CustomizerHttpHeaders.APPID) // header 名
.description("应用id") // 描述
.in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header
.schema(new StringSchema()._default("1").name(CustomizerHttpHeaders.APPID).description("appid"))))
.addOperationCustomizer((operation, handlerMethod) -> operation
.addParametersItem(new Parameter()
.name(CustomizerHttpHeaders.NONCE) // header 名
.description("随机数,不少于10位") // 描述
.in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header
.schema(new StringSchema()._default("1111111111111").name(CustomizerHttpHeaders.NONCE).description("nonce"))))
.addOperationCustomizer((operation, handlerMethod) -> operation
.addParametersItem(new Parameter()
.name(CustomizerHttpHeaders.TIMESTAMP) // header 名
.description("时间戳,与服务器时间不相差10min") // 描述
.in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header
.schema(new StringSchema()._default("1745472001234").name(CustomizerHttpHeaders.TIMESTAMP).description("timestamp"))))
.addOperationCustomizer((operation, handlerMethod) -> operation
.addParametersItem(new Parameter()
.name(CustomizerHttpHeaders.SIGN) // header 名
.description("时间戳,与服务器时间不相差10min") // 描述
.in(String.valueOf(SecurityScheme.In.HEADER)) // 请求 header
.schema(new StringSchema()._default("fndjfhqofhjdsafsalfbshab").name(CustomizerHttpHeaders.SIGN).description("sign"))))
.build();
}
}
......@@ -44,6 +44,8 @@ public class ComputilityWebAutoConfiguration implements WebMvcConfigurer {
public void configurePathMatch(PathMatchConfigurer configurer) {
configurePathMatch(configurer, webProperties.getAdminApi());
configurePathMatch(configurer, webProperties.getAppApi());
configurePathMatch(configurer, webProperties.getOpenApi());
}
/**
......
......@@ -21,6 +21,9 @@ public class WebProperties {
@NotNull(message = "Admin API 不能为空")
private Api adminApi = new Api("/admin-api", "**.controller.admin.**");
@NotNull(message = "Open API 不能为空")
private Api openApi = new Api("/open-api", "**.controller.openapi.**");
@NotNull(message = "Admin UI 不能为空")
private Ui adminUi;
......
......@@ -21,7 +21,7 @@ public abstract class ApiRequestFilter extends OncePerRequestFilter {
protected boolean shouldNotFilter(HttpServletRequest request) {
// 只过滤 API 请求的地址
String apiUri = request.getRequestURI().substring(request.getContextPath().length());
return !StrUtil.startWithAny(apiUri, webProperties.getAdminApi().getPrefix(), webProperties.getAppApi().getPrefix());
return !StrUtil.startWithAny(apiUri, webProperties.getAdminApi().getPrefix(), webProperties.getAppApi().getPrefix(), webProperties.getOpenApi().getPrefix());
}
}
......@@ -115,6 +115,7 @@ public class WebFrameworkUtils {
if (request.getServletPath().startsWith(properties.getAppApi().getPrefix())) {
return UserTypeEnum.MEMBER.getValue();
}
return null;
}
......
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>computility</artifactId>
<groupId>com.luhu</groupId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>computility-module-external</artifactId>
<packaging>jar</packaging>
<name>${project.artifactId}</name>
<dependencies>
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-common</artifactId>
</dependency>
<!-- Web 相关 -->
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-spring-boot-starter-protection</artifactId>
</dependency>
<!-- DB 相关 -->
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-spring-boot-starter-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-spring-boot-starter-redis</artifactId>
</dependency>
<!-- 工具类相关 -->
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-spring-boot-starter-excel</artifactId>
</dependency>
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-spring-boot-starter-biz-tenant</artifactId>
</dependency>
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-module-infra</artifactId>
<version>${revision}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-module-system</artifactId>
<version>${revision}</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
package com.luhu.computility.module.external;
/**
* @version 1.0
* @Author ljq
* @Date 2025/4/16
* @注释
*/
public interface AppCredentialsApi {
/**
* 根据appId获得外部应用鉴权信息
*
* @param appId 编号
* @return 外部应用鉴权信息
*/
String getAppSecretByAppid(String appId);
}
package com.luhu.computility.module.external;
import com.luhu.computility.framework.common.exception.ErrorCode;
public interface ExternalResponseCode {
ErrorCode SUCCESS = new ErrorCode(200, "成功");
// ========== 客户端错误段 ==========
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
ErrorCode NOT_FOUND = new ErrorCode(404, "请求未找到");
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
// ========== 服务端错误段 ==========
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "");
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
ErrorCode ERROR_CONFIGURATION = new ErrorCode(502, "错误的配置项");
// ========== 自定义错误段 ==========
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
ErrorCode ERROR_IMAGE = new ErrorCode(1000, "没有接收到合适的图片文件,请确认上传的是jpg、png、jpeg格式的图片文");
}
package com.luhu.computility.module.external.api;
/**
* 转发AI相关 API 接口
*
* @author ljq
*/
public interface AiServiceApi {
String imageComparison(String Url);
}
package com.luhu.computility.module.external.api;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
/**
* AiService API 实现类
*
* @author ljq
*/
@Service
@Validated
public class AiServiceApiImpl implements AiServiceApi {
@Override
public String imageComparison(String Url) {
return null;
}
}
package com.luhu.computility.module.external.controller.admin.appcredentials;
import com.luhu.computility.framework.apilog.core.annotation.ApiAccessLog;
import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.framework.common.pojo.PageParam;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.common.util.object.BeanUtils;
import com.luhu.computility.framework.excel.core.util.ExcelUtils;
import com.luhu.computility.module.external.controller.admin.appcredentials.vo.AppCredentialsPageReqVO;
import com.luhu.computility.module.external.controller.admin.appcredentials.vo.AppCredentialsRespVO;
import com.luhu.computility.module.external.controller.admin.appcredentials.vo.AppCredentialsSaveReqVO;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import com.luhu.computility.module.external.dal.dataobject.appcredentials.AppCredentialsDO;
import com.luhu.computility.module.external.service.appcredentials.AppCredentialsService;
import static com.luhu.computility.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.luhu.computility.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 外部应用鉴权信息")
@RestController
@RequestMapping("/external/app-credentials")
@Validated
public class AppCredentialsController {
@Resource
private AppCredentialsService appCredentialsService;
@PostMapping("/create")
@Operation(summary = "创建外部应用鉴权信息")
@PreAuthorize("@ss.hasPermission('external:app-credentials:create')")
public CommonResult<Long> createAppCredentials(@Valid @RequestBody AppCredentialsSaveReqVO createReqVO) {
return success(appCredentialsService.createAppCredentials(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新外部应用鉴权信息")
@PreAuthorize("@ss.hasPermission('external:app-credentials:update')")
public CommonResult<Boolean> updateAppCredentials(@Valid @RequestBody AppCredentialsSaveReqVO updateReqVO) {
appCredentialsService.updateAppCredentials(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除外部应用鉴权信息")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('external:app-credentials:delete')")
public CommonResult<Boolean> deleteAppCredentials(@RequestParam("id") Long id) {
appCredentialsService.deleteAppCredentials(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得外部应用鉴权信息")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('external:app-credentials:query')")
public CommonResult<AppCredentialsRespVO> getAppCredentials(@RequestParam("id") Long id) {
AppCredentialsDO appCredentials = appCredentialsService.getAppCredentials(id);
return success(BeanUtils.toBean(appCredentials, AppCredentialsRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得外部应用鉴权信息分页")
@PreAuthorize("@ss.hasPermission('external:app-credentials:query')")
public CommonResult<PageResult<AppCredentialsRespVO>> getAppCredentialsPage(@Valid AppCredentialsPageReqVO pageReqVO) {
PageResult<AppCredentialsDO> pageResult = appCredentialsService.getAppCredentialsPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, AppCredentialsRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出外部应用鉴权信息 Excel")
@PreAuthorize("@ss.hasPermission('external:app-credentials:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportAppCredentialsExcel(@Valid AppCredentialsPageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<AppCredentialsDO> list = appCredentialsService.getAppCredentialsPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "外部应用鉴权信息.xls", "数据", AppCredentialsRespVO.class,
BeanUtils.toBean(list, AppCredentialsRespVO.class));
}
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.admin.appcredentials.vo;
import com.luhu.computility.framework.common.pojo.PageParam;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.luhu.computility.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 外部应用鉴权信息分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class AppCredentialsPageReqVO extends PageParam {
@Schema(description = "应用名", example = "王五")
private String appName;
@Schema(description = "应用id", example = "6835")
private String appId;
@Schema(description = "应用密钥")
private String appSecret;
@Schema(description = "备注", example = "你说的对")
private String remark;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.admin.appcredentials.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 外部应用鉴权信息 Response VO")
@Data
@ExcelIgnoreUnannotated
public class AppCredentialsRespVO {
@Schema(description = "参数主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "26230")
@ExcelProperty("参数主键")
private Long id;
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@ExcelProperty("应用名")
private String appName;
@Schema(description = "应用id", requiredMode = Schema.RequiredMode.REQUIRED, example = "6835")
@ExcelProperty("应用id")
private String appId;
@Schema(description = "应用密钥", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("应用密钥")
private String appSecret;
@Schema(description = "备注", example = "你说的对")
@ExcelProperty("备注")
private String remark;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.admin.appcredentials.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
@Schema(description = "管理后台 - 外部应用鉴权信息新增/修改 Request VO")
@Data
public class AppCredentialsSaveReqVO {
@Schema(description = "参数主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "26230")
private Long id;
@Schema(description = "应用名", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
@NotEmpty(message = "应用名不能为空")
private String appName;
@Schema(description = "应用id", requiredMode = Schema.RequiredMode.REQUIRED, example = "6835")
@NotEmpty(message = "应用id不能为空")
private String appId;
@Schema(description = "应用密钥", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "应用密钥不能为空")
private String appSecret;
@Schema(description = "备注", example = "你说的对")
private String remark;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.admin.file;
import com.luhu.computility.framework.apilog.core.annotation.ApiAccessLog;
import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.framework.common.pojo.PageParam;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.common.util.object.BeanUtils;
import com.luhu.computility.framework.excel.core.util.ExcelUtils;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFilePageReqVO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFileRespVO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFileSaveReqVO;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import com.luhu.computility.module.external.service.file.AiGeneratedFileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
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.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import static com.luhu.computility.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static com.luhu.computility.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - ai换脸-生成文件")
@RestController
@RequestMapping("/external/ai-generated-file")
@Validated
public class AiGeneratedFileController {
@Resource
private AiGeneratedFileService aiGeneratedFileService;
@PostMapping("/create")
@Operation(summary = "创建ai换脸-生成文件")
@PreAuthorize("@ss.hasPermission('external:ai-generated-file:create')")
public CommonResult<Integer> createAiGeneratedFile(@Valid @RequestBody AiGeneratedFileSaveReqVO createReqVO) {
return success(aiGeneratedFileService.createAiGeneratedFile(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新ai换脸-生成文件")
@PreAuthorize("@ss.hasPermission('external:ai-generated-file:update')")
public CommonResult<Boolean> updateAiGeneratedFile(@Valid @RequestBody AiGeneratedFileSaveReqVO updateReqVO) {
aiGeneratedFileService.updateAiGeneratedFile(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除ai换脸-生成文件")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('external:ai-generated-file:delete')")
public CommonResult<Boolean> deleteAiGeneratedFile(@RequestParam("id") Integer id) {
aiGeneratedFileService.deleteAiGeneratedFile(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得ai换脸-生成文件")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('external:ai-generated-file:query')")
public CommonResult<AiGeneratedFileRespVO> getAiGeneratedFile(@RequestParam("id") Integer id) {
AiGeneratedFileDO aiGeneratedFile = aiGeneratedFileService.getAiGeneratedFile(id);
return success(BeanUtils.toBean(aiGeneratedFile, AiGeneratedFileRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得ai换脸-生成文件分页")
@PreAuthorize("@ss.hasPermission('external:ai-generated-file:query')")
public CommonResult<PageResult<AiGeneratedFileRespVO>> getAiGeneratedFilePage(@Valid AiGeneratedFilePageReqVO pageReqVO) {
PageResult<AiGeneratedFileDO> pageResult = aiGeneratedFileService.getAiGeneratedFilePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, AiGeneratedFileRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出ai换脸-生成文件 Excel")
@PreAuthorize("@ss.hasPermission('external:ai-generated-file:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportAiGeneratedFileExcel(@Valid AiGeneratedFilePageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<AiGeneratedFileDO> list = aiGeneratedFileService.getAiGeneratedFilePage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "ai换脸-生成文件.xls", "数据", AiGeneratedFileRespVO.class,
BeanUtils.toBean(list, AiGeneratedFileRespVO.class));
}
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.admin.file.vo;
import com.luhu.computility.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static com.luhu.computility.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - ai换脸-生成文件分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class AiGeneratedFilePageReqVO extends PageParam {
@Schema(description = "任务id", example = "21088")
private String promptId;
@Schema(description = "文件类型 1.图片 2.视频", example = "2")
private Integer type;
@Schema(description = "文件生成状态 1.未开始 2.上传中 3.已上传 ", example = "2")
private Integer status;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.admin.file.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.luhu.computility.framework.excel.core.annotations.DictFormat;
import com.luhu.computility.framework.excel.core.convert.DictConvert;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - ai换脸-生成文件 Response VO")
@Data
@ExcelIgnoreUnannotated
public class AiGeneratedFileRespVO {
@Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "28105")
@ExcelProperty("自增主键")
private Integer id;
@Schema(description = "任务id", requiredMode = Schema.RequiredMode.REQUIRED, example = "21088")
@ExcelProperty("任务id")
private String promptId;
@Schema(description = "文件类型 1.图片 2.视频", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty(value = "文件类型 1.图片 2.视频", converter = DictConvert.class)
@DictFormat("ai_generated_file") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
private Integer type;
@Schema(description = "文件生成状态 1.未开始 2.上传中 3.已上传 ", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty(value = "文件生成状态 1.未开始 2.上传中 3.已上传 ", converter = DictConvert.class)
@DictFormat("ai_generated_file_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
private Integer status;
@Schema(description = "oss存储地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
@ExcelProperty("oss存储地址")
private String url;
@Schema(description = "原始地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
@ExcelProperty("原始地址")
private String originalUrl;
@Schema(description = "缩略图/首帧地址")
@ExcelProperty("缩略图/首帧地址")
private String coverImage;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.admin.file.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "管理后台 - ai换脸-生成文件新增/修改 Request VO")
@Data
public class AiGeneratedFileSaveReqVO {
@Schema(description = "自增主键", example = "28105")
private Integer id;
@Schema(description = "任务id", requiredMode = Schema.RequiredMode.REQUIRED, example = "21088")
private String promptId;
@Schema(description = "文件类型 1.图片 2.视频", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer type;
@Schema(description = "文件生成状态 1.未开始 2.上传中 3.已上传 ", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Integer status;
@Schema(description = "oss存储地址", example = "https://www.iocoder.cn")
private String url;
@Schema(description = "原始地址", example = "https://www.iocoder.cn")
private String originalUrl;
@Schema(description = "缩略图/首帧地址")
private String coverImage;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.enums;
/**
* @version 1.0
* @Author ljq
* @Date 2025/6/17
* @注释
*/
public enum AiGeneratedFileStatus {
// 文件生成状态 1.未开始 2.上传中 3.已上传
UNSTART(1, "未开始"),
UPLOADING(2, "上传中"),
FINISHED(3, "已上传"),
FAILED(4, "上传失败");
private int value;
private String remark;
private AiGeneratedFileStatus(int value, String remark) {
this.value = value;
this.remark = remark;
}
public int getValue() {
return value;
}
public String getRemark() {
return remark;
}
public static AiGeneratedFileStatus getByValue(int value) {
for (AiGeneratedFileStatus o : AiGeneratedFileStatus.values()) {
if (o.getValue() == value) {
return o;
}
}
return null;
}
}
package com.luhu.computility.module.external.controller.enums;
/**
* @version 1.0
* @Author ljq
* @Date 2025/6/17
* @注释
*/
public enum AiGeneratedFileType {
// 文件类型 1.图片 2.视频
IMAGE(1, "图片"),
VIDEO(2, "视频");
private int value;
private String remark;
private AiGeneratedFileType(int value, String remark) {
this.value = value;
this.remark = remark;
}
public int getValue() {
return value;
}
public String getRemark() {
return remark;
}
public static AiGeneratedFileType getByValue(int value) {
for (AiGeneratedFileType o : AiGeneratedFileType.values()) {
if (o.getValue() == value) {
return o;
}
}
return null;
}
}
package com.luhu.computility.module.external.controller.enums;
import com.luhu.computility.framework.common.exception.ErrorCode;
/**
* External 错误码枚举类
*
* product 系统,使用 1_009_111_000 段
*/
public interface ErrorCodeConstants {
ErrorCode APPID_ERROR_NOT_EXISTS = new ErrorCode(1_009_111_001, "appid错误或不存在");
ErrorCode CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_009_111_002, "父分类不存在");
ErrorCode AI_GENERATED_FILE_NOT_EXISTS = new ErrorCode(1_009_111_003, "ai换脸-生成文件不存在");
}
package com.luhu.computility.module.external.controller.openapi;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.luhu.computility.framework.apilog.core.annotation.ApiAccessLog;
import com.luhu.computility.framework.common.exception.ServiceException;
import com.luhu.computility.framework.common.exception.enums.GlobalResponseCodeConstants;
import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.framework.common.util.http.HttpUtils;
import com.luhu.computility.module.external.controller.openapi.dto.ImageRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.PoetryImageReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.TextToImageReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ImageRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.PoetryImageReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.TextToImageReqDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Value;
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;
import static com.luhu.computility.framework.common.pojo.CommonResult.error;
import static com.luhu.computility.framework.common.pojo.CommonResult.success;
/**
* @version 1.0
* @Author ljq
* @Date 2025/4/28
* @注释
*/
@Tag(name = "调取新aigc接口")
@RestController
@RequestMapping("/external/v2")
public class AigcNewApiController {
@Value("${new-aigc.text-to-image-v2}")
private String textToImageV2;
@Value("${new-aigc.poetry-v2}")
private String textToImageByPoetryV2;
@ApiAccessLog
@PostMapping(value = "/text-to-image/season")
@Operation(summary = "四季和景点id生成图", description = "接收简单生图参数,将生成图片保存在本地服务器,并返回生成图片的url")
//@ApiSignature
public CommonResult<ImageRespDTO> textToImageV2(@RequestBody TextToImageReqDTO textToImageReqDTO){
try {
String requestBody = JSONUtil.toJsonStr(textToImageReqDTO);
String result = HttpUtils.post(textToImageV2, null, requestBody);
return textToImageBySeasonResponseResult(result);
}catch (Exception e){
Integer errorCode = GlobalResponseCodeConstants.INTERNAL_SERVER_ERROR.getCode();
String errorMsg = GlobalResponseCodeConstants.INTERNAL_SERVER_ERROR.getMsg();
if (e instanceof ServiceException) {
ServiceException serviceException = (ServiceException) e;
errorCode = serviceException.getCode();
errorMsg = serviceException.getMessage();
}
return error(errorCode, errorMsg);
}
}
@ApiAccessLog
@PostMapping("/text-to-image/poetry")
@Operation(summary = "获取藏头诗图片", description = "接收关键词、景点id、省份id这些参数,返回藏头诗图片url")
//@ApiSignature
public CommonResult<ImageRespDTO> textToImageByPoetry(@RequestBody PoetryImageReqDTO poetryImageReqDTO){
try {
String requestBody = JSONUtil.toJsonStr(poetryImageReqDTO);
String result = HttpUtils.post(textToImageByPoetryV2, null, requestBody);
return textToImageBySeasonResponseResult(result);
}catch (Exception e) {
Integer errorCode = GlobalResponseCodeConstants.INTERNAL_SERVER_ERROR.getCode();
String errorMsg = GlobalResponseCodeConstants.INTERNAL_SERVER_ERROR.getMsg();
return error(errorCode, errorMsg);
}
}
public CommonResult<ImageRespDTO> textToImageBySeasonResponseResult(String result) {
JSONObject resultJson = JSONUtil.parseObj(result);
Integer responseCode = (Integer) resultJson.get("code");
if (responseCode.equals(GlobalResponseCodeConstants.EXTERNAL_SUCCESS.getCode())) {
ImageRespDTO textToImageRespDTO = JSONUtil.toBean((JSONObject) resultJson.get("result"), ImageRespDTO.class);
return success(textToImageRespDTO);
} else {
return error((Integer) resultJson.get("code"), (String)resultJson.get("message"));
}
}
public <T> CommonResult<T> handleJsonObjectResult(String result, Class<T> clazz) {
JSONObject resultJson = JSONUtil.parseObj(result);
Integer responseCode = (Integer) resultJson.get("code");
if (responseCode.equals(GlobalResponseCodeConstants.EXTERNAL_SUCCESS.getCode())) {
T data = JSONUtil.toBean((JSONObject) resultJson.get("data"), clazz);
return success(data);
} else {
return error((Integer) resultJson.get("code"), (String) resultJson.get("message"));
}
}
}
package com.luhu.computility.module.external.controller.openapi;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.luhu.computility.framework.apilog.core.annotation.ApiAccessLog;
import com.luhu.computility.framework.common.exception.ServiceException;
import com.luhu.computility.framework.common.exception.enums.GlobalResponseCodeConstants;
import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.framework.common.util.http.HttpUtils;
import com.luhu.computility.module.external.controller.openapi.dto.ImageRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.PoetryImageReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.TextToImageReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ImageRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.PoetryImageReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.TextToImageReqDTO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Value;
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;
import static com.luhu.computility.framework.common.pojo.CommonResult.error;
import static com.luhu.computility.framework.common.pojo.CommonResult.success;
/**
* @version 1.0
* @Author ljq
* @Date 2025/4/28
* @注释
*/
@Tag(name = "调取前aigc接口")
@RestController
@RequestMapping("/external/v1")
public class AigcOldApiController {
@Value("${text-to-image.season}")
private String textToImageBySeason;
@Value("${text-to-image.file-name}")
private String textToImageByFileName;
@Value("${text-to-image.poetry}")
private String textToImageByPoetry;
@ApiAccessLog
@PostMapping(value = "/text-to-image/season")
@Operation(summary = "四季和景点id生成图", description = "接收简单生图参数,将生成图片保存在本地服务器,并返回生成图片的url")
//@ApiSignature
public CommonResult<ImageRespDTO> textToImageBySeason(@RequestBody TextToImageReqDTO textToImageReqDTO){
try {
String requestBody = JSONUtil.toJsonStr(textToImageReqDTO);
String result = HttpUtils.post(textToImageBySeason, null, requestBody);
return textToImageBySeasonResponseResult(result);
}catch (Exception e){
Integer errorCode = GlobalResponseCodeConstants.INTERNAL_SERVER_ERROR.getCode();
String errorMsg = GlobalResponseCodeConstants.INTERNAL_SERVER_ERROR.getMsg();
if (e instanceof ServiceException) {
ServiceException serviceException = (ServiceException) e;
errorCode = serviceException.getCode();
errorMsg = serviceException.getMessage();
}
return error(errorCode, errorMsg);
}
}
@ApiAccessLog
@PostMapping("/text-to-image/poetry")
@Operation(summary = "获取藏头诗图片", description = "接收关键词、景点id、省份id这些参数,返回藏头诗图片url")
//@ApiSignature
public CommonResult<ImageRespDTO> textToImageByPoetry(@RequestBody PoetryImageReqDTO poetryImageReqDTO){
try {
String requestBody = JSONUtil.toJsonStr(poetryImageReqDTO);
String result = HttpUtils.post(textToImageByPoetry, null, requestBody);
return textToImageBySeasonResponseResult(result);
}catch (Exception e) {
Integer errorCode = GlobalResponseCodeConstants.INTERNAL_SERVER_ERROR.getCode();
String errorMsg = GlobalResponseCodeConstants.INTERNAL_SERVER_ERROR.getMsg();
return error(errorCode, errorMsg);
}
}
public CommonResult<ImageRespDTO> textToImageBySeasonResponseResult(String result) {
JSONObject resultJson = JSONUtil.parseObj(result);
Integer responseCode = (Integer) resultJson.get("code");
if (responseCode.equals(GlobalResponseCodeConstants.EXTERNAL_SUCCESS.getCode())) {
ImageRespDTO textToImageRespDTO = JSONUtil.toBean((JSONObject) resultJson.get("result"), ImageRespDTO.class);
return success(textToImageRespDTO);
} else {
return error((Integer) resultJson.get("code"), (String)resultJson.get("message"));
}
}
public <T> CommonResult<T> handleJsonObjectResult(String result, Class<T> clazz) {
JSONObject resultJson = JSONUtil.parseObj(result);
Integer responseCode = (Integer) resultJson.get("code");
if (responseCode.equals(GlobalResponseCodeConstants.EXTERNAL_SUCCESS.getCode())) {
T data = JSONUtil.toBean((JSONObject) resultJson.get("data"), clazz);
return success(data);
} else {
return error((Integer) resultJson.get("code"), (String) resultJson.get("message"));
}
}
}
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
import java.util.List;
@Data
public class AIQAReqDTO {
// 用户提的问题
private String text;
//历史消息
private List<MessageDTO> message;
//知识库id
private List<String> pipelineIds;
//查询时所用的标签
private List<String> tags;
//查询时使用的文档ID。传入文档ID时,还需要传入文档所属的知识库ID才会生效
private List<String> fileIds;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class AIQARespDTO {
//请求唯一标识
private String requestId;
// 回答的问题
private String text;
//输入消耗token数
private String inputTokens;
//输出消耗token数
private String outputTokens;
//历史对话记录(包含最新对话)
private String messages;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class AIQAStreamRespDTO {
//内容
private String content;
//事件名称
private String eventName;
private MetadataDTO metadata;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class CeateVideoStreamReqDTO {
//文件名
private String fileName;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class CeateVideoStreamRespDTO {
//请求唯一标识
private String clientId;
//生成视频的唯一标识
private String promptId;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class ConversationReqDTO {
//问题
private String text;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class ConversationRespDTO {
//回答
private String text;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class GenerateFaceSwapRespDTO {
//请求唯一标识
private String clientId;
//生成视频/图片的唯一标识
private String promptId;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
import java.util.List;
@Data
public class ImageRespDTO {
private List<String> images;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
@Data
public class MatchImageReqDTO {
private MultipartFile image;
private String url;
private Integer limit;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class MatchImageRespDTO {
//相似度
private Double score;
// 简介,用来对应应用端的文章id
private String brief;
//模型返回的图片签名,图形在数据资源库的唯一id
private String cont_sign;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class MessageDTO {
//角色
private String role;
// 内容
private String content;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
import java.util.List;
@Data
public class MetadataDTO {
//请求唯一标识
private String requestID;
//历史对话记录(包含最新对话)
private List<MessageDTO> messages;
//输入消耗token数
private String inputTokens;
// 回答的问题
private String text;
//输出消耗token数
private String outputTokens;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* @version 1.0
* @Author ljq
* @Date 2025/7/16
* @注释
*/
@Data
public class NewAigcTextToImageV2ReqDTO {
@JsonProperty("scenic_spot_id")
private Integer scenicSpotId;
@JsonProperty("category")
private Integer category;
@JsonProperty("season")
private Integer season;
@JsonProperty("addition_content")
private List<String> additionContent;
@JsonProperty("image_count")
private Integer imageCount;
}
package com.luhu.computility.module.external.controller.openapi.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* @version 1.0
* @Author ljq
* @Date 2025/7/16
* @注释
*/
@Data
public class NewPoetryImageV2ReqDTO {
@JsonProperty("keyword")
private String keyword;
@JsonProperty("province_id")
private Integer provinceId;
@JsonProperty("scenic_spot_id")
private Integer scenicSpotId;
}
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class PoetryImageReqDTO {
private String keyword;
private Integer province_id;
private Integer scenic_spot_id;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
import java.util.List;
@Data
public class TextToImageReqDTO {
private Integer scenic_spot_id;
private Integer category;
private Integer season;
private Integer artistic_style;
private List<String> addition_content;
private Integer image_count;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
import org.springframework.web.multipart.MultipartFile;
@Data
public class UploadImageReqDTO {
private MultipartFile image;
private String url;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class UploadImageRespDTO {
//图片文件名
private String imageFileName;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class ViewImageReqDTO {
//视频流id
private String promptId;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class ViewSourceRespDTO {
//视频/图片地址
private String url;
private String coverImage;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.dto;
import lombok.Data;
@Data
public class ViewVideoReqDTO {
//视频流id
private String promptId;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.service;
import com.luhu.computility.framework.common.pojo.CommonResult;
import com.luhu.computility.module.external.controller.openapi.dto.AIQAReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.AIQARespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.CeateVideoStreamReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.CeateVideoStreamRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.GenerateFaceSwapRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ViewImageReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ViewVideoReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.AIQAReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.AIQARespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.CeateVideoStreamReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.CeateVideoStreamRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ConversationReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ConversationRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.GenerateFaceSwapRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.MatchImageRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.UploadImageRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ViewImageReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ViewVideoReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.ViewSourceRespDTO;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.List;
/**
* 转发- Service 接口
*
* @author 智慧导览
*/
public interface OpenApiService {
CommonResult<ConversationRespDTO> digitalHumanConversation(ConversationReqDTO conversationReqDTO);
CommonResult<UploadImageRespDTO> uploadFaceSwapImage(MultipartFile image, String url);
CommonResult<CeateVideoStreamRespDTO> ceateVideoStream(CeateVideoStreamReqDTO ceateVideoStreamReqDTO);
CommonResult<GenerateFaceSwapRespDTO> faceVideoGenerate(MultipartFile image, String url);
CommonResult<ViewSourceRespDTO> viewVideo(ViewVideoReqDTO viewVideoReqDTO);
CommonResult<GenerateFaceSwapRespDTO> faceImageGenerate(MultipartFile sourceImage, String sourceImageUrl,
MultipartFile targetImage, String targetImageUrl);
CommonResult<ViewSourceRespDTO> viewImage(ViewImageReqDTO viewImageReqDTO);
CommonResult<List<MatchImageRespDTO>> matchImage(MultipartFile image, String url, Integer limit, String cityId, String touristAreaId);
CommonResult<AIQARespDTO> AIQAChat(AIQAReqDTO aiqaReqDTO);
SseEmitter AIQAStreamChat(AIQAReqDTO aiqaReqDTO);
SseEmitter aliyunStreamChat(AIQAReqDTO aiqaReqDTO);
String getSourceUrl(String promptId, Integer type);
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.openapi.vo;
import lombok.Data;
@Data
public class AIQAStreamRespVO {
//内容
private String content;
//
private String eventName;
}
\ No newline at end of file
package com.luhu.computility.module.external.controller.service;
/**
* @version 1.0
* @Author ljq
* @Date 2025/4/28
* @注释
*/
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.luhu.computility.module.external.controller.openapi.dto.AIQAReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.AIQAStreamRespDTO;
import com.luhu.computility.module.external.controller.openapi.dto.AIQAReqDTO;
import com.luhu.computility.module.external.controller.openapi.dto.AIQAStreamRespDTO;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
@Service
public class SSEService {
private final WebClient webClient;
private final BlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
private AIQAStreamRespDTO aiqaStreamRespDTO;
public SSEService() {
this.webClient = WebClient.create();
}
public Flux<AIQAStreamRespDTO> receiveSSEStream(String url, AIQAReqDTO aiqaReqDTO) {
return webClient.post()
.uri(url)
.contentType(MediaType.APPLICATION_JSON) // 设置请求体的Content-Type为JSON
.bodyValue(aiqaReqDTO)
.retrieve()
.bodyToFlux(ServerSentEvent.class)
.map(response -> {
System.out.println(response.event());
System.out.println(response.data());
JSONObject data = JSONUtil.parseObj(response.data());
aiqaStreamRespDTO = JSONUtil.toBean(data, AIQAStreamRespDTO.class);
//针对源端的error进行处理,如果事件名称包含error,为了给用户一个好的体验,返回一个用户看得懂的语句
if (response.event().contains("error")) {
aiqaStreamRespDTO.setEventName("complete");
aiqaStreamRespDTO.setContent("当前系统访问人数较多,请稍后试试...");
} else {
aiqaStreamRespDTO.setEventName(response.event());
}
/* if (!ObjectUtils.isEmpty(data.get("content"))) {
aiqaStreamRespDTO.setContent((String)data.get("content"));
}
if (!ObjectUtils.isEmpty(data.get("messages"))) {
aiqaStreamRespDTO.setMessages(JsonUtils.parseArray((String) data.get("messages"), MessageDTO.class));
}*/
return aiqaStreamRespDTO;
})
.filter(result -> {
//content有内容或者eventName为complete
return !ObjectUtils.isEmpty(aiqaStreamRespDTO.getContent()) || "complete".equals(result.getEventName());
});
}
//备用方法
public String backUp(String response) {
String[] lines = response.split("\n");
JSONObject jsonObject = JSONUtil.parseObj(response);
if (!StringUtils.isEmpty((String)jsonObject.get("content")) && "null".equals((String)jsonObject.get("content"))) {
}
StringBuilder message = new StringBuilder();
for (String line : lines) {
if (line.startsWith("content: ")) {
message.append(line.substring(6)).append("\n");
} else if (line.isEmpty() && message.length() > 0) {
String completeMessage = message.toString().trim();
message.setLength(0);
return completeMessage;
}
}
return null;
}
}
\ No newline at end of file
package com.luhu.computility.module.external.dal.dataobject.appcredentials;
import com.luhu.computility.framework.mybatis.core.dataobject.BaseDO;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
/**
* 外部应用鉴权信息 DO
*
* @author 芋道源码
*/
@TableName("external_app_credentials")
@KeySequence("external_app_credentials_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AppCredentialsDO extends BaseDO {
/**
* 参数主键
*/
@TableId
private Long id;
/**
* 应用名
*/
private String appName;
/**
* 应用id
*/
private String appId;
/**
* 应用密钥
*/
private String appSecret;
/**
* 备注
*/
private String remark;
}
\ No newline at end of file
package com.luhu.computility.module.external.dal.dataobject.file;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.luhu.computility.framework.mybatis.core.dataobject.BaseDO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* ai换脸-生成文件 DO
*
* @author 智慧导览
*/
@TableName("external_file")
@KeySequence("external_file_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AiGeneratedFileDO extends BaseDO {
/**
* 自增主键
*/
@TableId
private Integer id;
/**
* 任务id
*/
private String promptId;
/**
* 文件类型 1.图片 2.视频
*
*/
private Integer type;
/**
* 文件生成状态 1.未开始 2.上传中 3.已上传
*
*/
private Integer status;
/**
* oss存储地址
*/
private String url;
/**
* 原始存储地址
*/
private String originalUrl;
/**
* 缩略图/首帧地址
*/
private String coverImage;
}
\ No newline at end of file
package com.luhu.computility.module.external.dal.mysql.appcredentials;
import java.util.*;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.mybatis.core.mapper.BaseMapperX;
import com.luhu.computility.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.luhu.computility.module.external.controller.admin.appcredentials.vo.AppCredentialsPageReqVO;
import com.luhu.computility.module.external.dal.dataobject.appcredentials.AppCredentialsDO;
import com.luhu.computility.module.external.dal.dataobject.appcredentials.AppCredentialsDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 外部应用鉴权信息 Mapper
*
* @author 芋道源码
*/
@Mapper
public interface AppCredentialsMapper extends BaseMapperX<AppCredentialsDO> {
default PageResult<AppCredentialsDO> selectPage(AppCredentialsPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<AppCredentialsDO>()
.likeIfPresent(AppCredentialsDO::getAppName, reqVO.getAppName())
.eqIfPresent(AppCredentialsDO::getAppId, reqVO.getAppId())
.eqIfPresent(AppCredentialsDO::getAppSecret, reqVO.getAppSecret())
.eqIfPresent(AppCredentialsDO::getRemark, reqVO.getRemark())
.betweenIfPresent(AppCredentialsDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(AppCredentialsDO::getId));
}
}
\ No newline at end of file
package com.luhu.computility.module.external.dal.mysql.file;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.mybatis.core.mapper.BaseMapperX;
import com.luhu.computility.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFilePageReqVO;
import com.luhu.computility.module.external.controller.enums.AiGeneratedFileStatus;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFilePageReqVO;
import com.luhu.computility.module.external.controller.enums.AiGeneratedFileStatus;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* ai换脸-生成文件 Mapper
*
* @author 智慧导览
*/
@Mapper
public interface AiGeneratedFileMapper extends BaseMapperX<AiGeneratedFileDO> {
default PageResult<AiGeneratedFileDO> selectPage(AiGeneratedFilePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<AiGeneratedFileDO>()
.eqIfPresent(AiGeneratedFileDO::getPromptId, reqVO.getPromptId())
.eqIfPresent(AiGeneratedFileDO::getType, reqVO.getType())
.eqIfPresent(AiGeneratedFileDO::getStatus, reqVO.getStatus())
.betweenIfPresent(AiGeneratedFileDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(AiGeneratedFileDO::getId));
}
default AiGeneratedFileDO getAiGeneratedFileByPromptId(String promptId) {
return selectOne(new LambdaQueryWrapperX<AiGeneratedFileDO>()
.eqIfPresent(AiGeneratedFileDO::getPromptId, promptId));
}
default List<AiGeneratedFileDO> getAiGeneratedFileByStatus(Integer status) {
return selectList(new LambdaQueryWrapperX<AiGeneratedFileDO>()
.eqIfPresent(AiGeneratedFileDO::getStatus, status));
}
default List<AiGeneratedFileDO> selectPendingTasks() {
return selectList(new LambdaQueryWrapperX<AiGeneratedFileDO>()
.eq(AiGeneratedFileDO::getStatus, AiGeneratedFileStatus.UNSTART.getValue())
.isNotNull(AiGeneratedFileDO::getOriginalUrl)
.or().eq(AiGeneratedFileDO::getStatus, AiGeneratedFileStatus.FAILED.getValue())
.last(" order by create_time desc limit 10"));
}
}
\ No newline at end of file
package com.luhu.computility.module.external.enums;
public enum CityEnum {
TIANSHUI("1", "t3gp1i7p7z"),
YUEYANG("3", "l6k1abp3yp"),
CHANGSHA("2", "fn3syzuf4a");
private String value;
private String remark;
private CityEnum(String value, String remark) {
this.value = value;
this.remark = remark;
}
public String getValue() {
return value;
}
public String getRemark() {
return remark;
}
public static CityEnum getByValue(String value) {
for (CityEnum o : CityEnum.values()) {
if (o.getValue() .equals(value) ) {
return o;
}
}
return null;
}
}
package com.luhu.computility.module.external.eums;
/**
* Infra 字典类型的枚举类
*
* @author 芋道源码
*/
public interface DictDataConstants {
String VIDEO_SUFFIX = "video_suffix";
String IMAGE_SUFFIX = "image_suffix";
}
package com.luhu.computility.module.external.eums;
/**
* Infra 字典类型的枚举类
*
* @author 芋道源码
*/
public interface DictTypeConstants {
String FILE_SUFFIX = "file_suffix";
}
package com.luhu.computility.module.external.job;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.luhu.computility.framework.quartz.core.handler.JobHandler;
import com.luhu.computility.framework.tenant.core.aop.TenantIgnore;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFileSaveReqVO;
import com.luhu.computility.module.external.controller.enums.AiGeneratedFileStatus;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFileSaveReqVO;
import com.luhu.computility.module.external.controller.enums.AiGeneratedFileStatus;
import com.luhu.computility.module.external.controller.openapi.service.OpenApiService;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import com.luhu.computility.module.external.service.file.AiGeneratedFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* @version 1.0
* @Author ljq
* @Date 2025/6/17
* @ 定时查找模型已处理的视频,上传到oss并将新地址更新到数据库
*/
@Component
@Slf4j
public class UpdateAiGeneratedFileStatusJob implements JobHandler {
@Resource
private AiGeneratedFileService aiGeneratedFileService;
@Resource
private OpenApiService openApiService;
@Override
@TenantIgnore
public String execute(String param) {
List<AiGeneratedFileDO> aiGeneratedFileList = aiGeneratedFileService.getAiGeneratedFileByStatus(AiGeneratedFileStatus.UNSTART.getValue());
int num = 0;
if (!CollectionUtil.isEmpty(aiGeneratedFileList)){
for (AiGeneratedFileDO aiGeneratedFileDO : aiGeneratedFileList) {
String originalUrl = openApiService.getSourceUrl(aiGeneratedFileDO.getPromptId(), aiGeneratedFileDO.getType());
if (!ObjectUtil.isEmpty(originalUrl)) {
aiGeneratedFileService.updateAiGeneratedFile(new AiGeneratedFileSaveReqVO()
.setId(aiGeneratedFileDO.getId())
.setOriginalUrl(originalUrl));
num++;
}
}
}
return StrUtil.format("更新数量:", num);
}
}
package com.luhu.computility.module.external.job;
import cn.hutool.core.util.StrUtil;
import com.luhu.computility.framework.quartz.core.handler.JobHandler;
import com.luhu.computility.framework.tenant.core.aop.TenantIgnore;
import com.luhu.computility.module.external.service.file.AiGeneratedFileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @version 1.0
* @Author ljq
* @Date 2025/6/17
* @ 定时查找模型已处理的视频,上传到oss并将新地址更新到数据库
*/
@Component
@Slf4j
public class UploadAiGeneratedFileJob implements JobHandler {
@Resource
private AiGeneratedFileService aiGeneratedFileService;
@Override
@TenantIgnore
public String execute(String param) {
aiGeneratedFileService.startUploadTask();
return StrUtil.format("更新数量:", "updateDOList.size()");
}
}
package com.luhu.computility.module.external.service.appcredentials;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.luhu.computility.framework.common.exception.ServiceException;
import com.luhu.computility.module.external.AppCredentialsApi;
import com.luhu.computility.module.external.AppCredentialsApi;
import com.luhu.computility.module.external.controller.enums.ErrorCodeConstants;
import com.luhu.computility.module.external.dal.dataobject.appcredentials.AppCredentialsDO;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import static com.luhu.computility.module.external.controller.enums.ErrorCodeConstants.APPID_ERROR_NOT_EXISTS;
/**
* @version 1.0
* @Author ljq
* @Date 2025/4/16
* @注释
*/
@Service
@Validated
public class AppCredentialsApiImpl implements AppCredentialsApi {
@Resource
private AppCredentialsService appCredentialsService;
@Override
public String getAppSecretByAppid(String appId) {
String appSecret = appCredentialsService.getAppSecretByAppid(appId);
if (StringUtils.isEmpty(appSecret)) {
throw new ServiceException(APPID_ERROR_NOT_EXISTS);
}
return appSecret;
}
}
package com.luhu.computility.module.external.service.appcredentials;
import java.util.*;
import javax.validation.*;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.module.external.controller.admin.appcredentials.vo.AppCredentialsPageReqVO;
import com.luhu.computility.module.external.controller.admin.appcredentials.vo.AppCredentialsSaveReqVO;
import com.luhu.computility.module.external.dal.dataobject.appcredentials.AppCredentialsDO;
import com.luhu.computility.module.external.dal.dataobject.appcredentials.AppCredentialsDO;
/**
* 外部应用鉴权信息 Service 接口
*
* @author 芋道源码
*/
public interface AppCredentialsService {
/**
* 创建外部应用鉴权信息
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createAppCredentials(@Valid AppCredentialsSaveReqVO createReqVO);
/**
* 更新外部应用鉴权信息
*
* @param updateReqVO 更新信息
*/
void updateAppCredentials(@Valid AppCredentialsSaveReqVO updateReqVO);
/**
* 删除外部应用鉴权信息
*
* @param id 编号
*/
void deleteAppCredentials(Long id);
/**
* 获得外部应用鉴权信息
*
* @param id 编号
* @return 外部应用鉴权信息
*/
AppCredentialsDO getAppCredentials(Long id);
/**
* 获得外部应用鉴权信息分页
*
* @param pageReqVO 分页查询
* @return 外部应用鉴权信息分页
*/
PageResult<AppCredentialsDO> getAppCredentialsPage(AppCredentialsPageReqVO pageReqVO);
String getAppSecretByAppid(String appId);
}
\ No newline at end of file
package com.luhu.computility.module.external.service.appcredentials;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.luhu.computility.framework.common.exception.ServiceException;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.common.util.object.BeanUtils;
import com.luhu.computility.module.external.controller.admin.appcredentials.vo.AppCredentialsPageReqVO;
import com.luhu.computility.module.external.controller.admin.appcredentials.vo.AppCredentialsSaveReqVO;
import com.luhu.computility.module.external.dal.dataobject.appcredentials.AppCredentialsDO;
import com.luhu.computility.module.external.dal.mysql.appcredentials.AppCredentialsMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import com.luhu.computility.module.external.dal.dataobject.appcredentials.AppCredentialsDO;
import com.luhu.computility.module.external.dal.mysql.appcredentials.AppCredentialsMapper;
import static com.luhu.computility.module.external.controller.enums.ErrorCodeConstants.APPID_ERROR_NOT_EXISTS;
/**
* 外部应用鉴权信息 Service 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class AppCredentialsServiceImpl implements AppCredentialsService {
@Resource
private AppCredentialsMapper appCredentialsMapper;
@Override
public Long createAppCredentials(AppCredentialsSaveReqVO createReqVO) {
// 插入
AppCredentialsDO appCredentials = BeanUtils.toBean(createReqVO, AppCredentialsDO.class);
appCredentialsMapper.insert(appCredentials);
// 返回
return appCredentials.getId();
}
@Override
public void updateAppCredentials(AppCredentialsSaveReqVO updateReqVO) {
// 校验存在
validateAppCredentialsExists(updateReqVO.getId());
// 更新
AppCredentialsDO updateObj = BeanUtils.toBean(updateReqVO, AppCredentialsDO.class);
appCredentialsMapper.updateById(updateObj);
}
@Override
public void deleteAppCredentials(Long id) {
// 校验存在
validateAppCredentialsExists(id);
// 删除
appCredentialsMapper.deleteById(id);
}
private void validateAppCredentialsExists(Long id) {
if (appCredentialsMapper.selectById(id) == null) {
}
}
@Override
public AppCredentialsDO getAppCredentials(Long id) {
return appCredentialsMapper.selectById(id);
}
@Override
public PageResult<AppCredentialsDO> getAppCredentialsPage(AppCredentialsPageReqVO pageReqVO) {
return appCredentialsMapper.selectPage(pageReqVO);
}
@Override
public String getAppSecretByAppid(String appId) {
AppCredentialsDO appCredentialsDO = appCredentialsMapper.selectOne(Wrappers.<AppCredentialsDO>lambdaQuery()
.eq(AppCredentialsDO::getAppId, appId));
if (ObjectUtil.isEmpty(appCredentialsDO)) {
throw new ServiceException(APPID_ERROR_NOT_EXISTS);
}
return appCredentialsDO.getAppSecret();
}
}
\ No newline at end of file
package com.luhu.computility.module.external.service.file;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFilePageReqVO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFileSaveReqVO;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFilePageReqVO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFileSaveReqVO;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import javax.validation.Valid;
import java.util.List;
/**
* ai换脸-生成文件 Service 接口
*
* @author 智慧导览
*/
public interface AiGeneratedFileService {
/**
* 创建ai换脸-生成文件
*
* @param createReqVO 创建信息
* @return 编号
*/
Integer createAiGeneratedFile(@Valid AiGeneratedFileSaveReqVO createReqVO);
/**
* 更新ai换脸-生成文件
*
* @param updateReqVO 更新信息
*/
void updateAiGeneratedFile(@Valid AiGeneratedFileSaveReqVO updateReqVO);
/**
* 删除ai换脸-生成文件
*
* @param id 编号
*/
void deleteAiGeneratedFile(Integer id);
/**
* 获得ai换脸-生成文件
*
* @param id 编号
* @return ai换脸-生成文件
*/
AiGeneratedFileDO getAiGeneratedFile(Integer id);
/**
* 获得ai换脸-生成文件分页
*
* @param pageReqVO 分页查询
* @return ai换脸-生成文件分页
*/
PageResult<AiGeneratedFileDO> getAiGeneratedFilePage(AiGeneratedFilePageReqVO pageReqVO);
/**
* 获得ai换脸-生成文件
*
* @param promptId 任务编号
* @return ai换脸-生成文件
*/
AiGeneratedFileDO getAiGeneratedFileByPromptId(String promptId);
List<AiGeneratedFileDO> getAiGeneratedFileByStatus(Integer status);
//开始上传
void startUploadTask();
}
\ No newline at end of file
package com.luhu.computility.module.external.service.file;
import cn.hutool.core.io.IoUtil;
import com.luhu.computility.framework.common.exception.ServiceException;
import com.luhu.computility.framework.common.pojo.PageResult;
import com.luhu.computility.framework.common.util.object.BeanUtils;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFilePageReqVO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFileSaveReqVO;
import com.luhu.computility.module.external.controller.enums.AiGeneratedFileStatus;
import com.luhu.computility.module.external.controller.enums.AiGeneratedFileType;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import com.luhu.computility.module.external.dal.mysql.file.AiGeneratedFileMapper;
import com.luhu.computility.module.infra.api.file.FileApi;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFilePageReqVO;
import com.luhu.computility.module.external.controller.admin.file.vo.AiGeneratedFileSaveReqVO;
import com.luhu.computility.module.external.controller.enums.AiGeneratedFileStatus;
import com.luhu.computility.module.external.controller.enums.AiGeneratedFileType;
import com.luhu.computility.module.external.controller.enums.ErrorCodeConstants;
import com.luhu.computility.module.external.dal.dataobject.file.AiGeneratedFileDO;
import com.luhu.computility.module.external.dal.mysql.file.AiGeneratedFileMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StreamUtils;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* ai换脸-生成文件 Service 实现类
*
* @author 智慧导览
*/
@Service
@Validated
public class AiGeneratedFileServiceImpl implements AiGeneratedFileService {
private static final Logger log = LoggerFactory.getLogger(AiGeneratedFileServiceImpl.class);
@Resource
private AiGeneratedFileMapper aiGeneratedFileMapper;
@Autowired
private FileApi fileApi;
private final BlockingQueue<AiGeneratedFileDO> uploadQueue = new LinkedBlockingQueue<>();
@Resource(name = "videoUploadExecutor")
private Executor executor;
private final AtomicBoolean isUploading = new AtomicBoolean(false);
@Override
public Integer createAiGeneratedFile(AiGeneratedFileSaveReqVO createReqVO) {
// 插入
AiGeneratedFileDO aiGeneratedFile = BeanUtils.toBean(createReqVO, AiGeneratedFileDO.class);
aiGeneratedFileMapper.insert(aiGeneratedFile);
// 返回
return aiGeneratedFile.getId();
}
@Override
public void updateAiGeneratedFile(AiGeneratedFileSaveReqVO updateReqVO) {
// 校验存在
validateAiGeneratedFileExists(updateReqVO.getId());
// 更新
AiGeneratedFileDO updateObj = BeanUtils.toBean(updateReqVO, AiGeneratedFileDO.class);
aiGeneratedFileMapper.updateById(updateObj);
}
@Override
public void deleteAiGeneratedFile(Integer id) {
// 校验存在
validateAiGeneratedFileExists(id);
// 删除
aiGeneratedFileMapper.deleteById(id);
}
private void validateAiGeneratedFileExists(Integer id) {
if (aiGeneratedFileMapper.selectById(id) == null) {
throw new ServiceException(ErrorCodeConstants.AI_GENERATED_FILE_NOT_EXISTS);
}
}
@Override
public AiGeneratedFileDO getAiGeneratedFile(Integer id) {
return aiGeneratedFileMapper.selectById(id);
}
@Override
public PageResult<AiGeneratedFileDO> getAiGeneratedFilePage(AiGeneratedFilePageReqVO pageReqVO) {
return aiGeneratedFileMapper.selectPage(pageReqVO);
}
@Override
public AiGeneratedFileDO getAiGeneratedFileByPromptId(String promptId) {
return aiGeneratedFileMapper.getAiGeneratedFileByPromptId(promptId);
}
@Override
public List<AiGeneratedFileDO> getAiGeneratedFileByStatus(Integer status) {
return aiGeneratedFileMapper.getAiGeneratedFileByStatus(status);
}
@Override
public void startUploadTask() {
if (isUploading.get()) {
return;
}
List<AiGeneratedFileDO> aiGeneratedFileDOList = aiGeneratedFileMapper.selectPendingTasks();
if (CollectionUtils.isEmpty(aiGeneratedFileDOList)) {
return;
}
uploadQueue.addAll(aiGeneratedFileDOList);
isUploading.set(true);
executor.execute(this::processQueue); // 启动上传
}
//开始执行队列
private void processQueue() {
try {
while (!uploadQueue.isEmpty()) {
AiGeneratedFileDO aiGeneratedFileDO = uploadQueue.poll();
if (aiGeneratedFileDO != null) {
try {
String fileUrl = aiGeneratedFileDO.getOriginalUrl();
aiGeneratedFileDO.setStatus(AiGeneratedFileStatus.UPLOADING.getValue());
aiGeneratedFileMapper.updateById(aiGeneratedFileDO);
// 1. 下载到临时文件
String fileName = getFileNameFromUrl(fileUrl);
File tempFile = File.createTempFile("oss-", getFileExtension(fileName));
System.out.println("存放的路径:"+tempFile.getAbsolutePath());
InputStream in = new URL(fileUrl).openStream();
OutputStream out = new FileOutputStream(tempFile);
StreamUtils.copy(in, out);
// 2. 通过 InputStream 上传到 OSS
InputStream uploadStream = new FileInputStream(tempFile);
String ossUrl = fileApi.createFile(IoUtil.readBytes(uploadStream));
aiGeneratedFileDO.setUrl(ossUrl);
if (aiGeneratedFileDO.getType().intValue() == AiGeneratedFileType.VIDEO.getValue()) {
aiGeneratedFileDO.setCoverImage(ossUrl + "?x-oss-process=video/snapshot,t_0,f_jpg,w_0,h_0");
} else if (aiGeneratedFileDO.getType().intValue() == AiGeneratedFileType.IMAGE.getValue()) {
aiGeneratedFileDO.setCoverImage(ossUrl + "?x-oss-process=image/resize,p_30");
}
log.error(aiGeneratedFileDO.getCoverImage());
aiGeneratedFileDO.setStatus(AiGeneratedFileStatus.FINISHED.getValue());
// 3. 删除本地临时文件
boolean deleted = tempFile.delete();
if (!deleted) {
log.error("删除临时文件失败:{}", tempFile.getAbsolutePath());
}
} catch (Exception e) {
aiGeneratedFileDO.setStatus(AiGeneratedFileStatus.FAILED.getValue());
//task.setErrorMsg(e.getMessage());
log.error("上传失败,任务ID:{},错误:{}", aiGeneratedFileDO.getId(), e.getMessage(), e);
} finally {
aiGeneratedFileMapper.updateById(aiGeneratedFileDO);
}
}
}
} finally {
isUploading.set(false);
}
}
private String getFileNameFromUrl(String url) {
return url.substring(url.lastIndexOf("/") + 1);
}
private String getFileExtension(String fileName) {
int idx = fileName.lastIndexOf(".");
return (idx != -1) ? fileName.substring(idx) : ".tmp";
}
}
\ No newline at end of file
package com.luhu.computility.module.external.web.config;
import com.luhu.computility.framework.swagger.config.ComputilitySwaggerAutoConfiguration;
import org.springdoc.core.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* external 模块的 web 组件的 Configuration
*
* @author ljq
*/
@Configuration(proxyBeanMethods = false)
public class ExternalWebConfiguration {
/**
* external 模块的 API 分组
*/
@Bean
public GroupedOpenApi externalGroupedOpenApi() {
return ComputilitySwaggerAutoConfiguration.buildGroupedOpenApiAuthBySign("external");
}
}
package com.luhu.computility.module.external.web.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @version 1.0
* @Author ljq
* @Date 2025/6/17
* @注释
*/
@Configuration
public class ThreadPoolConfig {
/*
@Bean(name = "videoUploadExecutor")
public ExecutorService videoUploadExecutor() {
//监控线程池状态
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("video-upload-");
executor.initialize();
return Executors.newSingleThreadExecutor();
}*/
public static final String VIDEO_UPLOAD_EXECUTOR = "videoUploadExecutor";
@Bean(VIDEO_UPLOAD_EXECUTOR)
public ThreadPoolTaskExecutor videoUploadExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(1); // 单线程
executor.setMaxPoolSize(1); // 最大线程数
executor.setQueueCapacity(100); // 可根据实际设置
executor.setThreadNamePrefix("video-upload-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
executor.initialize();
return executor;
}
}
/**
* infra 模块的 web 配置
*/
package com.luhu.computility.module.external.web;
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>$com.luhu</groupId>
<artifactId>$computility-module-external</artifactId>
<version>$2.6.0-jdk8-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
package $com.luhu;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
}
package $com.luhu;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* Unit test for simple App.
*/
public class AppTest
extends TestCase
{
/**
* Create the test case
*
* @param testName name of the test case
*/
public AppTest( String testName )
{
super( testName );
}
/**
* @return the suite of tests being tested
*/
public static Test suite()
{
return new TestSuite( AppTest.class );
}
/**
* Rigourous Test :-)
*/
public void testApp()
{
assertTrue( true );
}
}
......@@ -37,6 +37,8 @@ public class SecurityConfiguration {
.requestMatchers(adminSeverContextPath + "/**").permitAll();
// 文件读取
registry.requestMatchers(buildAdminApi("/infra/file/*/get/**")).permitAll();
//模型返回数据转发
registry.requestMatchers(buildOpenApi("/external/**")).permitAll();
}
};
......
......@@ -41,11 +41,11 @@
<!-- 数据报表。默认注释,保证编译速度 -->
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-module-report</artifactId>
<version>${revision}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>com.luhu</groupId>-->
<!-- <artifactId>computility-module-report</artifactId>-->
<!-- <version>${revision}</version>-->
<!-- </dependency>-->
<!-- 工作流。默认注释,保证编译速度 -->
<!-- <dependency>-->
<!-- <groupId>com.luhu</groupId>-->
......@@ -97,6 +97,11 @@
<artifactId>computility-module-apihub</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.luhu</groupId>
<artifactId>computility-module-external</artifactId>
<version>${revision}</version>
</dependency>
<!-- CRM 相关模块。默认注释,保证编译速度 -->
......
......@@ -108,7 +108,7 @@ aj:
cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存
timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行
type: blockPuzzle # 验证码类型 default两种都实例化。 blockPuzzle 滑块拼图 clickWord 文字点选
water-mark: 芋道源码 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode
water-mark: 普惠算力 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode
interference-options: 0 # 滑动干扰项(0/1/2)
req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false
req-get-lock-limit: 5 # 验证失败 5 次,get接口锁定
......@@ -279,6 +279,7 @@ computility:
ignore-urls:
- /jmreport/* # 积木报表,无法携带租户编号
- /admin-api/infra/file/preview
- /open-api/external/**
ignore-visit-urls:
- /admin-api/system/user/profile/**
- /admin-api/system/auth/**
......@@ -329,6 +330,8 @@ computility:
- rep_demo_employee
- rep_demo_gongsi
- rep_demo_jianpiao
- external_app_credentials
- external_file
ignore-caches:
- user_role_ids
- permission_menu_ids
......@@ -371,4 +374,49 @@ computility:
debug: false
# 插件配置 TODO 芋艿:【IOT】需要处理下
pf4j:
pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录
\ No newline at end of file
pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录
digital-human-zhuxi:
conversation: http://117.157.192.95:8081/zx/llm/chat_sse
token: Basic emh1eGlAdHhnOndBSmNETDRMZVZ3QjlhdlV1OVJN
similar-image:
base-url: http://117.157.192.95:8082/appDemo
match-mage: ${similar-image.base-url}/matchImage
swap-face:
base-url: http://117.157.192.95:8082/appDemo
upload-image: ${swap-face.base-url}/uploadFaceSwapImage
create-video-stream: ${swap-face.base-url}/reActorFaceSwap
view-video: ${swap-face.base-url}/viewVideo
image-to-video: ${swap-face.base-url}/generateFaceSwap
image-to-image: ${swap-face.base-url}/generateImageFaceSwap
view-image: ${swap-face.base-url}/viewImg
AIQA-chat: ${swap-face.base-url}/v1/AIQA-chat
AIQA-stream-chat: ${swap-face.base-url}/v1/AIQA-stream-chat
aliyun-stream-chat: ${swap-face.base-url}/v1/aliyun-ai-chat
new-aigc:
base-url: http://117.157.192.95:8082/api
# 文生图v1
text-to-image-v1: ${new-aigc.base-url}/v1/t2i/txt2Img
# 获取生图进度
progress: ${new-aigc.base-url}/v1/t2i/progress
# 预测
predict: ${new-aigc.base-url}/v1/t2i/run/predict
# 获取藏头诗图片v1
poetry-v1: ${new-aigc.base-url}/v1/t2i/getPoetryImg
# 文生图v2(其岸)
text-to-image-v2: ${new-aigc.base-url}/v2/t2i/txt2Img/
# 获取藏头诗图片v2
poetry-v2: ${new-aigc.base-url}/v2/t2i/getPoetryImg
text-to-image:
base-url: http://218.77.58.8:8189/api
season: ${text-to-image.base-url}/v2/t2i/txt2Img/
file-name: ${text-to-image.base-url}/user/images/
poetry: ${text-to-image.base-url}/v2/t2i/getPoetryImg
\ No newline at end of file
......@@ -17,12 +17,13 @@
<module>computility-module-infra</module>
<module>computility-module-member</module>
<!-- <module>computility-module-bpm</module>-->
<module>computility-module-report</module>
<!-- <module>computility-module-report</module>-->
<!-- <module>computility-module-mp</module>-->
<module>computility-module-pay</module>
<module>computility-module-mall</module>
<module>computility-module-biz</module>
<module>computility-module-apihub</module>
<module>computility-module-external</module>
<!-- <module>computility-module-crm</module>-->
<!-- <module>computility-module-erp</module>-->
<!-- <module>computility-module-iot</module>-->
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment