diff --git a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WddApi.java b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WddApi.java index b5467002f4..66583f50af 100644 --- a/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WddApi.java +++ b/yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WddApi.java @@ -1,17 +1,26 @@ package cn.iocoder.yudao.framework.ai.core.model.wenduoduo.api; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.extern.slf4j.Slf4j; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpRequest; import org.springframework.http.HttpStatusCode; import org.springframework.http.MediaType; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.LocalDateTime; +import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; @@ -47,26 +56,24 @@ public class WddApi { .build(); } + /** - * 创建API令牌 + * 创建 token * - * @param apiKey API密钥 - * @param uid 用户ID - * @param limit 限制 - * @return API令牌 + * @param request 请求信息 + * @return token */ - public String createApiToken(String apiKey, String uid, Integer limit) { - CreateApiTokenRequest request = new CreateApiTokenRequest(uid, limit); + public String createApiToken(CreateTokenRequest request) { return this.webClient.post() .uri("/api/user/createApiToken") - .header("Api-Key", apiKey) - .body(Mono.just(request), CreateApiTokenRequest.class) + .header("Api-Key", request.apiKey) + .body(Mono.just(request), CreateTokenRequest.class) .retrieve() .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) .bodyToMono(ApiResponse.class) .handle((response, sink) -> { if (response.code != 0) { - sink.error(new IllegalStateException("创建apiToken异常," + response.message)); + sink.error(new IllegalStateException("创建 token 异常," + response.message)); return; } sink.next(response.data.get("token").toString()); @@ -74,259 +81,159 @@ public class WddApi { .block(); } + /** - * 解析文件数据 + * 创建任务 * - * @param apiToken API令牌 - * @param content 内容 - * @param fileUrl 文件URL - * @return 数据URL + * @param type 类型 + * @param content 内容 + * @param files 文件列表 + * @return 任务ID */ - public String parseFileData(String apiToken, String content, String fileUrl) { - ParseFileDataRequest request = new ParseFileDataRequest(content, fileUrl); + public ApiResponse createTask(String token, Integer type, String content, List files) { + MultiValueMap formData = new LinkedMultiValueMap<>(); + formData.add("type", type); + if (content != null) { + formData.add("content", content); + } + if (files != null) { + for (MultipartFile file : files) { + formData.add("file", file.getResource()); + } + } + return this.webClient.post() - .uri("/api/ppt/parseFileData") - .header("token", apiToken) - .body(Mono.just(request), ParseFileDataRequest.class) + .uri("/api/ppt/v2/createTask") + .header("token", token) + .contentType(MediaType.MULTIPART_FORM_DATA) + .body(BodyInserters.fromMultipartData(formData)) .retrieve() - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) + .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(formData)) .bodyToMono(ApiResponse.class) - .handle((response, sink) -> { - if (response.code != 0) { - sink.error(new IllegalStateException("解析文件或内容异常," + response.message)); - return; - } - sink.next(response.data.get("dataUrl").toString()); - }) .block(); } /** - * 生成大纲 + * 获取生成选项 * - * @param apiToken API令牌 - * @param subject 主题 - * @param dataUrl 数据URL - * @param prompt 提示词 - * @return 大纲内容 + * @param lang 语种 + * @return 生成选项 */ - public String generateOutline(String apiToken, String subject, String dataUrl, String prompt) { - GenerateOutlineRequest request = new GenerateOutlineRequest(subject, dataUrl, prompt); - return this.webClient.post() - .uri("/api/ppt/generateOutline") - .header("token", apiToken) - .body(Mono.just(request), GenerateOutlineRequest.class) + public Map getOptions(String lang) { + String uri = "/api/ppt/v2/options"; + if (lang != null) { + uri += "?lang=" + lang; + } + return this.webClient.get() + .uri(uri) .retrieve() - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) - .bodyToMono(String.class) + .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(null)) + .bodyToMono(new ParameterizedTypeReference() { + }) + .>handle((response, sink) -> { + if (response.code != 0) { + sink.error(new IllegalStateException("获取生成选项异常," + response.message)); + return; + } + sink.next(response.data); + }) .block(); } /** * 生成大纲内容 * - * @param apiToken API令牌 - * @param outlineMarkdown 大纲Markdown - * @param dataUrl 数据URL - * @param prompt 提示词 - * @return 大纲内容 + * @return 大纲内容流 */ - public String generateContent(String apiToken, String outlineMarkdown, String dataUrl, String prompt) { - GenerateContentRequest request = new GenerateContentRequest(outlineMarkdown, dataUrl, prompt); + public Flux> generateOutlineContent(String token, GenerateOutlineRequest request) { return this.webClient.post() - .uri("/api/ppt/generateContent") - .header("token", apiToken) - .body(Mono.just(request), GenerateContentRequest.class) + .uri("/api/ppt/v2/generateContent") + .header("token", token) + .body(Mono.just(request), GenerateOutlineRequest.class) .retrieve() .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) - .bodyToMono(String.class) - .block(); + .bodyToFlux(new ParameterizedTypeReference<>() { + }); } /** - * 异步生成大纲内容 + * 修改大纲内容 * - * @param apiToken API令牌 - * @param outlineMarkdown 大纲Markdown - * @param dataUrl 数据URL - * @param templateId 模板ID - * @param prompt 提示词 - * @return 大纲内容和PPT ID + * @param id 任务ID + * @param markdown 大纲内容markdown + * @param question 用户修改建议 + * @return 大纲内容流 */ - public Map asyncGenerateContent(String apiToken, String outlineMarkdown, String dataUrl, String templateId, String prompt) { - AsyncGenerateContentRequest request = new AsyncGenerateContentRequest(outlineMarkdown, dataUrl, templateId, prompt); + public Flux> updateOutlineContent(String token, String id, String markdown, String question) { + UpdateOutlineRequest request = new UpdateOutlineRequest(id, markdown, question); return this.webClient.post() - .uri("/api/ppt/generateContent") - .header("token", apiToken) - .body(Mono.just(request), AsyncGenerateContentRequest.class) + .uri("/api/ppt/v2/updateContent") + .header("token", token) + .body(Mono.just(request), UpdateOutlineRequest.class) .retrieve() .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) - .bodyToMono(new ParameterizedTypeReference>() { - }) - .block(); + .bodyToFlux(new ParameterizedTypeReference>() { + }); } - /** - * 随机获取一个模板ID - * - * @param apiToken API令牌 - * @return 模板ID - */ - public String randomOneTemplateId(String apiToken) { - RandomTemplateRequest request = new RandomTemplateRequest(1, new TemplateFilter(1)); - return this.webClient.post() - .uri("/api/ppt/randomTemplates") - .header("token", apiToken) - .body(Mono.just(request), RandomTemplateRequest.class) - .retrieve() - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) - .bodyToMono(ApiResponse.class) - .handle((response, sink) -> { - if (response.code != 0) { - sink.error(new IllegalStateException("获取模板异常," + response.message)); - return; - } - sink.next(((Map) ((Object[]) response.data.get("data"))[0]).get("id").toString()); - }) - .block(); - } - - /** - * 生成PPT - * - * @param apiToken API令牌 - * @param templateId 模板ID - * @param markdown Markdown内容 - * @param pptxProperty PPT属性 - * @return PPT信息 - */ - public Map generatePptx(String apiToken, String templateId, String markdown, boolean pptxProperty) { - GeneratePptxRequest request = new GeneratePptxRequest(templateId, markdown, pptxProperty); - return this.webClient.post() - .uri("/api/ppt/generatePptx") - .header("token", apiToken) - .body(Mono.just(request), GeneratePptxRequest.class) - .retrieve() - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) - .bodyToMono(ApiResponse.class) - .>handle((response, sink) -> { - if (response.code != 0) { - sink.error(new IllegalStateException("生成PPT异常," + response.message)); - return; - } - sink.next((Map) response.data.get("pptInfo")); - }) - .block(); - } - - /** - * 下载PPT - * - * @param apiToken API令牌 - * @param id PPT ID - * @return 下载信息 - */ - public Map downloadPptx(String apiToken, String id) { - DownloadPptxRequest request = new DownloadPptxRequest(id); - return this.webClient.post() - .uri("/api/ppt/downloadPptx") - .header("token", apiToken) - .body(Mono.just(request), DownloadPptxRequest.class) - .retrieve() - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) - .bodyToMono(ApiResponse.class) - .>handle((response, sink) -> { - if (response.code != 0) { - sink.error(new IllegalStateException("下载PPT异常," + response.message)); - return; - } - sink.next(response.data); - }) - .block(); - } - - /** - * 直接生成PPT - * - * @param apiToken API令牌 - * @param templateId 模板ID - * @param subject 主题 - * @param dataUrl 数据URL - * @param prompt 提示词 - * @param pptxProperty PPT属性 - * @return PPT信息 - */ - public Map directGeneratePptx(String apiToken, String templateId, String subject, String dataUrl, String prompt, boolean pptxProperty) { - DirectGeneratePptxRequest request = new DirectGeneratePptxRequest(false, templateId, subject, dataUrl, prompt, pptxProperty); - return this.webClient.post() - .uri("/api/ppt/directGeneratePptx") - .header("token", apiToken) - .body(Mono.just(request), DirectGeneratePptxRequest.class) - .retrieve() - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) - .bodyToMono(ApiResponse.class) - .>handle((response, sink) -> { - if (response.code != 0) { - sink.error(new IllegalStateException("生成PPT异常," + response.message)); - return; - } - sink.next((Map) response.data.get("pptInfo")); - }) - .block(); - } - - /** - * 查询所有PPT列表 - * - * @param apiToken API令牌 - * @param body 请求体 - * @return PPT列表 - */ - public Map listAllPptx(String apiToken, String body) { - return this.webClient.post() - .uri("/api/ppt/listAllPptx") - .header("token", apiToken) - .bodyValue(body) - .retrieve() - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(body)) - .bodyToMono(ApiResponse.class) - .>handle((response, sink) -> { - if (response.code != 0) { - sink.error(new IllegalStateException("查询所有PPT列表异常," + response.message)); - return; - } - sink.next(response.data); - }) - .block(); - } /** * 分页查询PPT模板 * - * @param apiToken API令牌 - * @param body 请求体 + * @param token 令牌 + * @param request 请求体 * @return 模板列表 */ - public Map getPptTemplates(String apiToken, String body) { + public PagePptTemplateInfo getPptTemplatePage(String token, TemplateQueryRequest request) { return this.webClient.post() .uri("/api/ppt/templates") - .header("token", apiToken) - .bodyValue(body) + .header("token", token) + .bodyValue(request) .retrieve() - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(body)) - .bodyToMono(ApiResponse.class) - .>handle((response, sink) -> { - if (response.code != 0) { - sink.error(new IllegalStateException("分页查询PPT模板异常," + response.message)); - return; - } - sink.next(response.data); + .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) + .bodyToMono(new ParameterizedTypeReference() { }) .block(); } + /** - * API响应 + * 生成PPT + * + * @return PPT信息 + */ + public PptInfo generatePptx(String token, GeneratePptxRequest request) { + return this.webClient.post() + .uri("/api/ppt/v2/generatePptx") + .header("token", token) + .body(Mono.just(request), GeneratePptxRequest.class) + .retrieve() + .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request)) + .bodyToMono(ApiResponse.class) + .handle((response, sink) -> { + if (response.code != 0) { + sink.error(new IllegalStateException("生成 PPT 异常," + response.message)); + return; + } + sink.next(Objects.requireNonNull(JsonUtils.parseObject(JsonUtils.toJsonString(response.data.get("pptInfo")), PptInfo.class))); + }) + .block(); + } + + + @JsonInclude(value = JsonInclude.Include.NON_NULL) + public record CreateTokenRequest( + String apiKey, + String uid, + Integer limit + ) { + public CreateTokenRequest(String apiKey) { + this(apiKey, null, null); + } + } + + /** + * API 通用响应 */ @JsonInclude(value = JsonInclude.Include.NON_NULL) public record ApiResponse( @@ -337,33 +244,13 @@ public class WddApi { } /** - * 创建API令牌请求 + * 创建任务 */ @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record CreateApiTokenRequest( - String uid, - Integer limit - ) { - } - - /** - * 解析文件数据请求 - */ - @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record ParseFileDataRequest( + public record CreateTaskRequest( + Integer type, String content, - String fileUrl - ) { - } - - /** - * 生成大纲请求 - */ - @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record GenerateOutlineRequest( - String subject, - String dataUrl, - String prompt + List files ) { } @@ -371,45 +258,24 @@ public class WddApi { * 生成大纲内容请求 */ @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record GenerateContentRequest( - String outlineMarkdown, - String dataUrl, + public record GenerateOutlineRequest( + String id, + String length, + String scene, + String audience, + String lang, String prompt ) { } /** - * 异步生成大纲内容请求 + * 修改大纲内容请求 */ @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record AsyncGenerateContentRequest( - String outlineMarkdown, - String dataUrl, - String templateId, - String prompt, - @JsonProperty("asyncGenPptx") boolean asyncGenPptx - ) { - public AsyncGenerateContentRequest(String outlineMarkdown, String dataUrl, String templateId, String prompt) { - this(outlineMarkdown, dataUrl, templateId, prompt, true); - } - } - - /** - * 随机模板请求 - */ - @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record RandomTemplateRequest( - Integer size, - TemplateFilter filters - ) { - } - - /** - * 模板过滤器 - */ - @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record TemplateFilter( - Integer type + public record UpdateOutlineRequest( + String id, + String markdown, + String question ) { } @@ -418,32 +284,90 @@ public class WddApi { */ @JsonInclude(value = JsonInclude.Include.NON_NULL) public record GeneratePptxRequest( + String id, String templateId, - @JsonProperty("outlineContentMarkdown") String outlineContentMarkdown, - boolean pptxProperty + String markdown ) { } - /** - * 下载PPT请求 - */ - @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record DownloadPptxRequest( - String id - ) { - } - /** - * 直接生成PPT请求 - */ @JsonInclude(value = JsonInclude.Include.NON_NULL) - public record DirectGeneratePptxRequest( - boolean stream, - String templateId, + public record PptInfo( + String id, + String name, String subject, - String dataUrl, - String prompt, - boolean pptxProperty + String coverUrl, + String fileUrl, + String templateId, + String pptxProperty, + String userId, + String userName, + int companyId, + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime updateTime, + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime createTime, + String createUser, + String updateUser ) { } -} \ No newline at end of file + + + @JsonInclude(value = JsonInclude.Include.NON_NULL) + public record TemplateQueryRequest( + int page, + int size, + Filter filters + ) { + @JsonInclude(value = JsonInclude.Include.NON_NULL) + public record Filter( + int type, + String category, + String style, + String themeColor + ) { + } + } + + + @JsonInclude(value = JsonInclude.Include.NON_NULL) + public record PagePptTemplateInfo( + List data, + String total + ) { + + } + + + @JsonInclude(value = JsonInclude.Include.NON_NULL) + public record PptTemplateInfo( + String id, + int type, + Integer subType, + String layout, + String category, + String style, + String themeColor, + String lang, + boolean animation, + String subject, + String coverUrl, + String fileUrl, + List pageCoverUrls, + String pptxProperty, + int sort, + int num, + Integer imgNum, + int isDeleted, + String userId, + int companyId, + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime updateTime, + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + LocalDateTime createTime, + String createUser, + String updateUser + ) { + } + +} \ No newline at end of file