Commit a82abed2b56f4c1bc07e8905b582bb4f3c7634b6

Authored by xiaoxin
1 parent ea1d9f00

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

yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WddApi.java
1 1 package cn.iocoder.yudao.framework.ai.core.model.wenduoduo.api;
2 2  
  3 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  4 +import com.fasterxml.jackson.annotation.JsonFormat;
3 5 import com.fasterxml.jackson.annotation.JsonInclude;
4   -import com.fasterxml.jackson.annotation.JsonProperty;
5 6 import lombok.extern.slf4j.Slf4j;
6 7 import org.springframework.core.ParameterizedTypeReference;
7 8 import org.springframework.http.HttpRequest;
8 9 import org.springframework.http.HttpStatusCode;
9 10 import org.springframework.http.MediaType;
  11 +import org.springframework.util.LinkedMultiValueMap;
  12 +import org.springframework.util.MultiValueMap;
  13 +import org.springframework.web.multipart.MultipartFile;
  14 +import org.springframework.web.reactive.function.BodyInserters;
10 15 import org.springframework.web.reactive.function.client.ClientResponse;
11 16 import org.springframework.web.reactive.function.client.WebClient;
  17 +import reactor.core.publisher.Flux;
12 18 import reactor.core.publisher.Mono;
13 19  
  20 +import java.time.LocalDateTime;
  21 +import java.util.List;
14 22 import java.util.Map;
  23 +import java.util.Objects;
15 24 import java.util.function.Function;
16 25 import java.util.function.Predicate;
17 26  
... ... @@ -47,26 +56,24 @@ public class WddApi {
47 56 .build();
48 57 }
49 58  
  59 +
50 60 /**
51   - * 创建API令牌
  61 + * 创建 token
52 62 *
53   - * @param apiKey API密钥
54   - * @param uid 用户ID
55   - * @param limit 限制
56   - * @return API令牌
  63 + * @param request 请求信息
  64 + * @return token
57 65 */
58   - public String createApiToken(String apiKey, String uid, Integer limit) {
59   - CreateApiTokenRequest request = new CreateApiTokenRequest(uid, limit);
  66 + public String createApiToken(CreateTokenRequest request) {
60 67 return this.webClient.post()
61 68 .uri("/api/user/createApiToken")
62   - .header("Api-Key", apiKey)
63   - .body(Mono.just(request), CreateApiTokenRequest.class)
  69 + .header("Api-Key", request.apiKey)
  70 + .body(Mono.just(request), CreateTokenRequest.class)
64 71 .retrieve()
65 72 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
66 73 .bodyToMono(ApiResponse.class)
67 74 .<String>handle((response, sink) -> {
68 75 if (response.code != 0) {
69   - sink.error(new IllegalStateException("创建apiToken异常," + response.message));
  76 + sink.error(new IllegalStateException("创建 token 异常," + response.message));
70 77 return;
71 78 }
72 79 sink.next(response.data.get("token").toString());
... ... @@ -74,259 +81,159 @@ public class WddApi {
74 81 .block();
75 82 }
76 83  
77   - /**
78   - * 解析文件数据
79   - *
80   - * @param apiToken API令牌
81   - * @param content 内容
82   - * @param fileUrl 文件URL
83   - * @return 数据URL
84   - */
85   - public String parseFileData(String apiToken, String content, String fileUrl) {
86   - ParseFileDataRequest request = new ParseFileDataRequest(content, fileUrl);
87   - return this.webClient.post()
88   - .uri("/api/ppt/parseFileData")
89   - .header("token", apiToken)
90   - .body(Mono.just(request), ParseFileDataRequest.class)
91   - .retrieve()
92   - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
93   - .bodyToMono(ApiResponse.class)
94   - .<String>handle((response, sink) -> {
95   - if (response.code != 0) {
96   - sink.error(new IllegalStateException("解析文件或内容异常," + response.message));
97   - return;
98   - }
99   - sink.next(response.data.get("dataUrl").toString());
100   - })
101   - .block();
102   - }
103 84  
104 85 /**
105   - * 生成大纲
  86 + * 创建任务
106 87 *
107   - * @param apiToken API令牌
108   - * @param subject 主题
109   - * @param dataUrl 数据URL
110   - * @param prompt 提示词
111   - * @return 大纲内容
  88 + * @param type 类型
  89 + * @param content 内容
  90 + * @param files 文件列表
  91 + * @return 任务ID
112 92 */
113   - public String generateOutline(String apiToken, String subject, String dataUrl, String prompt) {
114   - GenerateOutlineRequest request = new GenerateOutlineRequest(subject, dataUrl, prompt);
115   - return this.webClient.post()
116   - .uri("/api/ppt/generateOutline")
117   - .header("token", apiToken)
118   - .body(Mono.just(request), GenerateOutlineRequest.class)
119   - .retrieve()
120   - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
121   - .bodyToMono(String.class)
122   - .block();
123   - }
  93 + public ApiResponse createTask(String token, Integer type, String content, List<MultipartFile> files) {
  94 + MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
  95 + formData.add("type", type);
  96 + if (content != null) {
  97 + formData.add("content", content);
  98 + }
  99 + if (files != null) {
  100 + for (MultipartFile file : files) {
  101 + formData.add("file", file.getResource());
  102 + }
  103 + }
124 104  
125   - /**
126   - * 生成大纲内容
127   - *
128   - * @param apiToken API令牌
129   - * @param outlineMarkdown 大纲Markdown
130   - * @param dataUrl 数据URL
131   - * @param prompt 提示词
132   - * @return 大纲内容
133   - */
134   - public String generateContent(String apiToken, String outlineMarkdown, String dataUrl, String prompt) {
135   - GenerateContentRequest request = new GenerateContentRequest(outlineMarkdown, dataUrl, prompt);
136 105 return this.webClient.post()
137   - .uri("/api/ppt/generateContent")
138   - .header("token", apiToken)
139   - .body(Mono.just(request), GenerateContentRequest.class)
  106 + .uri("/api/ppt/v2/createTask")
  107 + .header("token", token)
  108 + .contentType(MediaType.MULTIPART_FORM_DATA)
  109 + .body(BodyInserters.fromMultipartData(formData))
140 110 .retrieve()
141   - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
142   - .bodyToMono(String.class)
  111 + .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(formData))
  112 + .bodyToMono(ApiResponse.class)
143 113 .block();
144 114 }
145 115  
146 116 /**
147   - * 异步生成大纲内容
  117 + * 获取生成选项
148 118 *
149   - * @param apiToken API令牌
150   - * @param outlineMarkdown 大纲Markdown
151   - * @param dataUrl 数据URL
152   - * @param templateId 模板ID
153   - * @param prompt 提示词
154   - * @return 大纲内容和PPT ID
  119 + * @param lang 语种
  120 + * @return 生成选项
155 121 */
156   - public Map<String, Object> asyncGenerateContent(String apiToken, String outlineMarkdown, String dataUrl, String templateId, String prompt) {
157   - AsyncGenerateContentRequest request = new AsyncGenerateContentRequest(outlineMarkdown, dataUrl, templateId, prompt);
158   - return this.webClient.post()
159   - .uri("/api/ppt/generateContent")
160   - .header("token", apiToken)
161   - .body(Mono.just(request), AsyncGenerateContentRequest.class)
  122 + public Map<String, Object> getOptions(String lang) {
  123 + String uri = "/api/ppt/v2/options";
  124 + if (lang != null) {
  125 + uri += "?lang=" + lang;
  126 + }
  127 + return this.webClient.get()
  128 + .uri(uri)
162 129 .retrieve()
163   - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
164   - .bodyToMono(new ParameterizedTypeReference<Map<String, Object>>() {
  130 + .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(null))
  131 + .bodyToMono(new ParameterizedTypeReference<ApiResponse>() {
165 132 })
166   - .block();
167   - }
168   -
169   - /**
170   - * 随机获取一个模板ID
171   - *
172   - * @param apiToken API令牌
173   - * @return 模板ID
174   - */
175   - public String randomOneTemplateId(String apiToken) {
176   - RandomTemplateRequest request = new RandomTemplateRequest(1, new TemplateFilter(1));
177   - return this.webClient.post()
178   - .uri("/api/ppt/randomTemplates")
179   - .header("token", apiToken)
180   - .body(Mono.just(request), RandomTemplateRequest.class)
181   - .retrieve()
182   - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
183   - .bodyToMono(ApiResponse.class)
184   - .<String>handle((response, sink) -> {
  133 + .<Map<String, Object>>handle((response, sink) -> {
185 134 if (response.code != 0) {
186   - sink.error(new IllegalStateException("获取模板异常," + response.message));
  135 + sink.error(new IllegalStateException("获取生成选项异常," + response.message));
187 136 return;
188 137 }
189   - sink.next(((Map<String, Object>) ((Object[]) response.data.get("data"))[0]).get("id").toString());
  138 + sink.next(response.data);
190 139 })
191 140 .block();
192 141 }
193 142  
194 143 /**
195   - * 生成PPT
  144 + * 生成大纲内容
196 145 *
197   - * @param apiToken API令牌
198   - * @param templateId 模板ID
199   - * @param markdown Markdown内容
200   - * @param pptxProperty PPT属性
201   - * @return PPT信息
  146 + * @return 大纲内容流
202 147 */
203   - public Map<String, Object> generatePptx(String apiToken, String templateId, String markdown, boolean pptxProperty) {
204   - GeneratePptxRequest request = new GeneratePptxRequest(templateId, markdown, pptxProperty);
  148 + public Flux<Map<String, Object>> generateOutlineContent(String token, GenerateOutlineRequest request) {
205 149 return this.webClient.post()
206   - .uri("/api/ppt/generatePptx")
207   - .header("token", apiToken)
208   - .body(Mono.just(request), GeneratePptxRequest.class)
  150 + .uri("/api/ppt/v2/generateContent")
  151 + .header("token", token)
  152 + .body(Mono.just(request), GenerateOutlineRequest.class)
209 153 .retrieve()
210 154 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
211   - .bodyToMono(ApiResponse.class)
212   - .<Map<String, Object>>handle((response, sink) -> {
213   - if (response.code != 0) {
214   - sink.error(new IllegalStateException("生成PPT异常," + response.message));
215   - return;
216   - }
217   - sink.next((Map<String, Object>) response.data.get("pptInfo"));
218   - })
219   - .block();
  155 + .bodyToFlux(new ParameterizedTypeReference<>() {
  156 + });
220 157 }
221 158  
222 159 /**
223   - * 下载PPT
  160 + * 修改大纲内容
224 161 *
225   - * @param apiToken API令牌
226   - * @param id PPT ID
227   - * @return 下载信息
  162 + * @param id 任务ID
  163 + * @param markdown 大纲内容markdown
  164 + * @param question 用户修改建议
  165 + * @return 大纲内容流
228 166 */
229   - public Map<String, Object> downloadPptx(String apiToken, String id) {
230   - DownloadPptxRequest request = new DownloadPptxRequest(id);
  167 + public Flux<Map<String, Object>> updateOutlineContent(String token, String id, String markdown, String question) {
  168 + UpdateOutlineRequest request = new UpdateOutlineRequest(id, markdown, question);
231 169 return this.webClient.post()
232   - .uri("/api/ppt/downloadPptx")
233   - .header("token", apiToken)
234   - .body(Mono.just(request), DownloadPptxRequest.class)
  170 + .uri("/api/ppt/v2/updateContent")
  171 + .header("token", token)
  172 + .body(Mono.just(request), UpdateOutlineRequest.class)
235 173 .retrieve()
236 174 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
237   - .bodyToMono(ApiResponse.class)
238   - .<Map<String, Object>>handle((response, sink) -> {
239   - if (response.code != 0) {
240   - sink.error(new IllegalStateException("下载PPT异常," + response.message));
241   - return;
242   - }
243   - sink.next(response.data);
244   - })
245   - .block();
  175 + .bodyToFlux(new ParameterizedTypeReference<Map<String, Object>>() {
  176 + });
246 177 }
247 178  
  179 +
248 180 /**
249   - * 直接生成PPT
  181 + * 分页查询PPT模板
250 182 *
251   - * @param apiToken API令牌
252   - * @param templateId 模板ID
253   - * @param subject 主题
254   - * @param dataUrl 数据URL
255   - * @param prompt 提示词
256   - * @param pptxProperty PPT属性
257   - * @return PPT信息
  183 + * @param token 令牌
  184 + * @param request 请求体
  185 + * @return 模板列表
258 186 */
259   - public Map<String, Object> directGeneratePptx(String apiToken, String templateId, String subject, String dataUrl, String prompt, boolean pptxProperty) {
260   - DirectGeneratePptxRequest request = new DirectGeneratePptxRequest(false, templateId, subject, dataUrl, prompt, pptxProperty);
  187 + public PagePptTemplateInfo getPptTemplatePage(String token, TemplateQueryRequest request) {
261 188 return this.webClient.post()
262   - .uri("/api/ppt/directGeneratePptx")
263   - .header("token", apiToken)
264   - .body(Mono.just(request), DirectGeneratePptxRequest.class)
  189 + .uri("/api/ppt/templates")
  190 + .header("token", token)
  191 + .bodyValue(request)
265 192 .retrieve()
266 193 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
267   - .bodyToMono(ApiResponse.class)
268   - .<Map<String, Object>>handle((response, sink) -> {
269   - if (response.code != 0) {
270   - sink.error(new IllegalStateException("生成PPT异常," + response.message));
271   - return;
272   - }
273   - sink.next((Map<String, Object>) response.data.get("pptInfo"));
  194 + .bodyToMono(new ParameterizedTypeReference<PagePptTemplateInfo>() {
274 195 })
275 196 .block();
276 197 }
277 198  
  199 +
278 200 /**
279   - * 查询所有PPT列表
  201 + * 生成PPT
280 202 *
281   - * @param apiToken API令牌
282   - * @param body 请求体
283   - * @return PPT列表
  203 + * @return PPT信息
284 204 */
285   - public Map<String, Object> listAllPptx(String apiToken, String body) {
  205 + public PptInfo generatePptx(String token, GeneratePptxRequest request) {
286 206 return this.webClient.post()
287   - .uri("/api/ppt/listAllPptx")
288   - .header("token", apiToken)
289   - .bodyValue(body)
  207 + .uri("/api/ppt/v2/generatePptx")
  208 + .header("token", token)
  209 + .body(Mono.just(request), GeneratePptxRequest.class)
290 210 .retrieve()
291   - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(body))
  211 + .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
292 212 .bodyToMono(ApiResponse.class)
293   - .<Map<String, Object>>handle((response, sink) -> {
  213 + .<PptInfo>handle((response, sink) -> {
294 214 if (response.code != 0) {
295   - sink.error(new IllegalStateException("查询所有PPT列表异常," + response.message));
  215 + sink.error(new IllegalStateException("生成 PPT 异常," + response.message));
296 216 return;
297 217 }
298   - sink.next(response.data);
  218 + sink.next(Objects.requireNonNull(JsonUtils.parseObject(JsonUtils.toJsonString(response.data.get("pptInfo")), PptInfo.class)));
299 219 })
300 220 .block();
301 221 }
302 222  
303   - /**
304   - * 分页查询PPT模板
305   - *
306   - * @param apiToken API令牌
307   - * @param body 请求体
308   - * @return 模板列表
309   - */
310   - public Map<String, Object> getPptTemplates(String apiToken, String body) {
311   - return this.webClient.post()
312   - .uri("/api/ppt/templates")
313   - .header("token", apiToken)
314   - .bodyValue(body)
315   - .retrieve()
316   - .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(body))
317   - .bodyToMono(ApiResponse.class)
318   - .<Map<String, Object>>handle((response, sink) -> {
319   - if (response.code != 0) {
320   - sink.error(new IllegalStateException("分页查询PPT模板异常," + response.message));
321   - return;
322   - }
323   - sink.next(response.data);
324   - })
325   - .block();
  223 +
  224 + @JsonInclude(value = JsonInclude.Include.NON_NULL)
  225 + public record CreateTokenRequest(
  226 + String apiKey,
  227 + String uid,
  228 + Integer limit
  229 + ) {
  230 + public CreateTokenRequest(String apiKey) {
  231 + this(apiKey, null, null);
  232 + }
326 233 }
327 234  
328 235 /**
329   - * API响应
  236 + * API 通用响应
330 237 */
331 238 @JsonInclude(value = JsonInclude.Include.NON_NULL)
332 239 public record ApiResponse(
... ... @@ -337,113 +244,130 @@ public class WddApi {
337 244 }
338 245  
339 246 /**
340   - * 创建API令牌请求
341   - */
342   - @JsonInclude(value = JsonInclude.Include.NON_NULL)
343   - public record CreateApiTokenRequest(
344   - String uid,
345   - Integer limit
346   - ) {
347   - }
348   -
349   - /**
350   - * 解析文件数据请求
  247 + * 创建任务
351 248 */
352 249 @JsonInclude(value = JsonInclude.Include.NON_NULL)
353   - public record ParseFileDataRequest(
  250 + public record CreateTaskRequest(
  251 + Integer type,
354 252 String content,
355   - String fileUrl
  253 + List<MultipartFile> files
356 254 ) {
357 255 }
358 256  
359 257 /**
360   - * 生成大纲请求
  258 + * 生成大纲内容请求
361 259 */
362 260 @JsonInclude(value = JsonInclude.Include.NON_NULL)
363 261 public record GenerateOutlineRequest(
364   - String subject,
365   - String dataUrl,
  262 + String id,
  263 + String length,
  264 + String scene,
  265 + String audience,
  266 + String lang,
366 267 String prompt
367 268 ) {
368 269 }
369 270  
370 271 /**
371   - * 生成大纲内容请求
  272 + * 修改大纲内容请求
372 273 */
373 274 @JsonInclude(value = JsonInclude.Include.NON_NULL)
374   - public record GenerateContentRequest(
375   - String outlineMarkdown,
376   - String dataUrl,
377   - String prompt
  275 + public record UpdateOutlineRequest(
  276 + String id,
  277 + String markdown,
  278 + String question
378 279 ) {
379 280 }
380 281  
381 282 /**
382   - * 异步生成大纲内容请求
  283 + * 生成PPT请求
383 284 */
384 285 @JsonInclude(value = JsonInclude.Include.NON_NULL)
385   - public record AsyncGenerateContentRequest(
386   - String outlineMarkdown,
387   - String dataUrl,
  286 + public record GeneratePptxRequest(
  287 + String id,
388 288 String templateId,
389   - String prompt,
390   - @JsonProperty("asyncGenPptx") boolean asyncGenPptx
  289 + String markdown
391 290 ) {
392   - public AsyncGenerateContentRequest(String outlineMarkdown, String dataUrl, String templateId, String prompt) {
393   - this(outlineMarkdown, dataUrl, templateId, prompt, true);
394   - }
395 291 }
396 292  
397   - /**
398   - * 随机模板请求
399   - */
400   - @JsonInclude(value = JsonInclude.Include.NON_NULL)
401   - public record RandomTemplateRequest(
402   - Integer size,
403   - TemplateFilter filters
404   - ) {
405   - }
406 293  
407   - /**
408   - * 模板过滤器
409   - */
410 294 @JsonInclude(value = JsonInclude.Include.NON_NULL)
411   - public record TemplateFilter(
412   - Integer type
  295 + public record PptInfo(
  296 + String id,
  297 + String name,
  298 + String subject,
  299 + String coverUrl,
  300 + String fileUrl,
  301 + String templateId,
  302 + String pptxProperty,
  303 + String userId,
  304 + String userName,
  305 + int companyId,
  306 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  307 + LocalDateTime updateTime,
  308 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  309 + LocalDateTime createTime,
  310 + String createUser,
  311 + String updateUser
413 312 ) {
414 313 }
415 314  
416   - /**
417   - * 生成PPT请求
418   - */
  315 +
419 316 @JsonInclude(value = JsonInclude.Include.NON_NULL)
420   - public record GeneratePptxRequest(
421   - String templateId,
422   - @JsonProperty("outlineContentMarkdown") String outlineContentMarkdown,
423   - boolean pptxProperty
  317 + public record TemplateQueryRequest(
  318 + int page,
  319 + int size,
  320 + Filter filters
424 321 ) {
  322 + @JsonInclude(value = JsonInclude.Include.NON_NULL)
  323 + public record Filter(
  324 + int type,
  325 + String category,
  326 + String style,
  327 + String themeColor
  328 + ) {
  329 + }
425 330 }
426 331  
427   - /**
428   - * 下载PPT请求
429   - */
  332 +
430 333 @JsonInclude(value = JsonInclude.Include.NON_NULL)
431   - public record DownloadPptxRequest(
432   - String id
  334 + public record PagePptTemplateInfo(
  335 + List<PptTemplateInfo> data,
  336 + String total
433 337 ) {
  338 +
434 339 }
435 340  
436   - /**
437   - * 直接生成PPT请求
438   - */
  341 +
439 342 @JsonInclude(value = JsonInclude.Include.NON_NULL)
440   - public record DirectGeneratePptxRequest(
441   - boolean stream,
442   - String templateId,
  343 + public record PptTemplateInfo(
  344 + String id,
  345 + int type,
  346 + Integer subType,
  347 + String layout,
  348 + String category,
  349 + String style,
  350 + String themeColor,
  351 + String lang,
  352 + boolean animation,
443 353 String subject,
444   - String dataUrl,
445   - String prompt,
446   - boolean pptxProperty
  354 + String coverUrl,
  355 + String fileUrl,
  356 + List<String> pageCoverUrls,
  357 + String pptxProperty,
  358 + int sort,
  359 + int num,
  360 + Integer imgNum,
  361 + int isDeleted,
  362 + String userId,
  363 + int companyId,
  364 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  365 + LocalDateTime updateTime,
  366 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
  367 + LocalDateTime createTime,
  368 + String createUser,
  369 + String updateUser
447 370 ) {
448 371 }
449   -}
450 372 \ No newline at end of file
  373 +
  374 +}
451 375 \ No newline at end of file
... ...