Преглед на файлове

【功能新增】AI:文多多对接

xiaoxin преди 5 месеца
родител
ревизия
ea1d9f0075

+ 449 - 0
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WddApi.java

@@ -0,0 +1,449 @@
+package cn.iocoder.yudao.framework.ai.core.model.wenduoduo.api;
+
+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.web.reactive.function.client.ClientResponse;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * 文多多 API
+ * <p>
+ * <p>
+ * * 对接文多多:<a href="https://docmee.cn/open-platform/api">PPT 生成 API</a>
+ *
+ * @author xiaoxin
+ */
+@Slf4j
+public class WddApi {
+
+    public static final String BASE_URL = "https://docmee.cn";
+
+    private final WebClient webClient;
+
+    private final Predicate<HttpStatusCode> STATUS_PREDICATE = status -> !status.is2xxSuccessful();
+
+    private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION =
+            reqParam -> response -> response.bodyToMono(String.class).handle((responseBody, sink) -> {
+                HttpRequest request = response.request();
+                log.error("[wdd-api] 调用失败!请求方式:[{}],请求地址:[{}],请求参数:[{}],响应数据: [{}]",
+                        request.getMethod(), request.getURI(), reqParam, responseBody);
+                sink.error(new IllegalStateException("[wdd-api] 调用失败!"));
+            });
+
+    public WddApi(String baseUrl) {
+        this.webClient = WebClient.builder()
+                .baseUrl(baseUrl)
+                .defaultHeaders((headers) -> headers.setContentType(MediaType.APPLICATION_JSON))
+                .build();
+    }
+
+    /**
+     * 创建API令牌
+     *
+     * @param apiKey API密钥
+     * @param uid    用户ID
+     * @param limit  限制
+     * @return API令牌
+     */
+    public String createApiToken(String apiKey, String uid, Integer limit) {
+        CreateApiTokenRequest request = new CreateApiTokenRequest(uid, limit);
+        return this.webClient.post()
+                .uri("/api/user/createApiToken")
+                .header("Api-Key", apiKey)
+                .body(Mono.just(request), CreateApiTokenRequest.class)
+                .retrieve()
+                .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
+                .bodyToMono(ApiResponse.class)
+                .<String>handle((response, sink) -> {
+                    if (response.code != 0) {
+                        sink.error(new IllegalStateException("创建apiToken异常," + response.message));
+                        return;
+                    }
+                    sink.next(response.data.get("token").toString());
+                })
+                .block();
+    }
+
+    /**
+     * 解析文件数据
+     *
+     * @param apiToken API令牌
+     * @param content  内容
+     * @param fileUrl  文件URL
+     * @return 数据URL
+     */
+    public String parseFileData(String apiToken, String content, String fileUrl) {
+        ParseFileDataRequest request = new ParseFileDataRequest(content, fileUrl);
+        return this.webClient.post()
+                .uri("/api/ppt/parseFileData")
+                .header("token", apiToken)
+                .body(Mono.just(request), ParseFileDataRequest.class)
+                .retrieve()
+                .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
+                .bodyToMono(ApiResponse.class)
+                .<String>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 大纲内容
+     */
+    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)
+                .retrieve()
+                .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
+                .bodyToMono(String.class)
+                .block();
+    }
+
+    /**
+     * 生成大纲内容
+     *
+     * @param apiToken        API令牌
+     * @param outlineMarkdown 大纲Markdown
+     * @param dataUrl         数据URL
+     * @param prompt          提示词
+     * @return 大纲内容
+     */
+    public String generateContent(String apiToken, String outlineMarkdown, String dataUrl, String prompt) {
+        GenerateContentRequest request = new GenerateContentRequest(outlineMarkdown, dataUrl, prompt);
+        return this.webClient.post()
+                .uri("/api/ppt/generateContent")
+                .header("token", apiToken)
+                .body(Mono.just(request), GenerateContentRequest.class)
+                .retrieve()
+                .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
+                .bodyToMono(String.class)
+                .block();
+    }
+
+    /**
+     * 异步生成大纲内容
+     *
+     * @param apiToken        API令牌
+     * @param outlineMarkdown 大纲Markdown
+     * @param dataUrl         数据URL
+     * @param templateId      模板ID
+     * @param prompt          提示词
+     * @return 大纲内容和PPT ID
+     */
+    public Map<String, Object> asyncGenerateContent(String apiToken, String outlineMarkdown, String dataUrl, String templateId, String prompt) {
+        AsyncGenerateContentRequest request = new AsyncGenerateContentRequest(outlineMarkdown, dataUrl, templateId, prompt);
+        return this.webClient.post()
+                .uri("/api/ppt/generateContent")
+                .header("token", apiToken)
+                .body(Mono.just(request), AsyncGenerateContentRequest.class)
+                .retrieve()
+                .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
+                .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
+                })
+                .block();
+    }
+
+    /**
+     * 随机获取一个模板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)
+                .<String>handle((response, sink) -> {
+                    if (response.code != 0) {
+                        sink.error(new IllegalStateException("获取模板异常," + response.message));
+                        return;
+                    }
+                    sink.next(((Map<String, Object>) ((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<String, Object> 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)
+                .<Map<String, Object>>handle((response, sink) -> {
+                    if (response.code != 0) {
+                        sink.error(new IllegalStateException("生成PPT异常," + response.message));
+                        return;
+                    }
+                    sink.next((Map<String, Object>) response.data.get("pptInfo"));
+                })
+                .block();
+    }
+
+    /**
+     * 下载PPT
+     *
+     * @param apiToken API令牌
+     * @param id       PPT ID
+     * @return 下载信息
+     */
+    public Map<String, Object> 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)
+                .<Map<String, Object>>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<String, Object> 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)
+                .<Map<String, Object>>handle((response, sink) -> {
+                    if (response.code != 0) {
+                        sink.error(new IllegalStateException("生成PPT异常," + response.message));
+                        return;
+                    }
+                    sink.next((Map<String, Object>) response.data.get("pptInfo"));
+                })
+                .block();
+    }
+
+    /**
+     * 查询所有PPT列表
+     *
+     * @param apiToken API令牌
+     * @param body     请求体
+     * @return PPT列表
+     */
+    public Map<String, Object> 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)
+                .<Map<String, Object>>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     请求体
+     * @return 模板列表
+     */
+    public Map<String, Object> getPptTemplates(String apiToken, String body) {
+        return this.webClient.post()
+                .uri("/api/ppt/templates")
+                .header("token", apiToken)
+                .bodyValue(body)
+                .retrieve()
+                .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(body))
+                .bodyToMono(ApiResponse.class)
+                .<Map<String, Object>>handle((response, sink) -> {
+                    if (response.code != 0) {
+                        sink.error(new IllegalStateException("分页查询PPT模板异常," + response.message));
+                        return;
+                    }
+                    sink.next(response.data);
+                })
+                .block();
+    }
+
+    /**
+     * API响应
+     */
+    @JsonInclude(value = JsonInclude.Include.NON_NULL)
+    public record ApiResponse(
+            Integer code,
+            String message,
+            Map<String, Object> data
+    ) {
+    }
+
+    /**
+     * 创建API令牌请求
+     */
+    @JsonInclude(value = JsonInclude.Include.NON_NULL)
+    public record CreateApiTokenRequest(
+            String uid,
+            Integer limit
+    ) {
+    }
+
+    /**
+     * 解析文件数据请求
+     */
+    @JsonInclude(value = JsonInclude.Include.NON_NULL)
+    public record ParseFileDataRequest(
+            String content,
+            String fileUrl
+    ) {
+    }
+
+    /**
+     * 生成大纲请求
+     */
+    @JsonInclude(value = JsonInclude.Include.NON_NULL)
+    public record GenerateOutlineRequest(
+            String subject,
+            String dataUrl,
+            String prompt
+    ) {
+    }
+
+    /**
+     * 生成大纲内容请求
+     */
+    @JsonInclude(value = JsonInclude.Include.NON_NULL)
+    public record GenerateContentRequest(
+            String outlineMarkdown,
+            String dataUrl,
+            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
+    ) {
+    }
+
+    /**
+     * 生成PPT请求
+     */
+    @JsonInclude(value = JsonInclude.Include.NON_NULL)
+    public record GeneratePptxRequest(
+            String templateId,
+            @JsonProperty("outlineContentMarkdown") String outlineContentMarkdown,
+            boolean pptxProperty
+    ) {
+    }
+
+    /**
+     * 下载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,
+            String subject,
+            String dataUrl,
+            String prompt,
+            boolean pptxProperty
+    ) {
+    }
+}