Commit e56b99f2a7cacc61ec78f5b6764037cb2dbf6f09

Authored by YunaiV
2 parents be416b7d 911f5f8b

Merge branch 'feature/ai' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17

yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WddPptApi.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/wenduoduo/api/WenDuoDuoPptApi.java
... ... @@ -8,6 +8,7 @@ import org.springframework.core.ParameterizedTypeReference;
8 8 import org.springframework.http.HttpRequest;
9 9 import org.springframework.http.HttpStatusCode;
10 10 import org.springframework.http.MediaType;
  11 +import org.springframework.util.Assert;
11 12 import org.springframework.util.LinkedMultiValueMap;
12 13 import org.springframework.util.MultiValueMap;
13 14 import org.springframework.web.multipart.MultipartFile;
... ... @@ -24,18 +25,17 @@ import java.util.Objects;
24 25 import java.util.function.Function;
25 26 import java.util.function.Predicate;
26 27  
27   -// TODO @新:要不改成 WenDuoDuoPptApi
28 28 /**
29 29 * 文多多 API
30 30 *
31   - * @see <a href="https://docmee.cn/open-platform/api">PPT 生成 API</a>
32   - *
33 31 * @author xiaoxin
  32 + * @see <a href="https://docmee.cn/open-platform/api">PPT 生成 API</a>
34 33 */
35 34 @Slf4j
36   -public class WddPptApi {
  35 +public class WenDuoDuoPptApi {
37 36  
38 37 public static final String BASE_URL = "https://docmee.cn";
  38 + public static final String TOKEN_NAME = "token";
39 39  
40 40 private final WebClient webClient;
41 41  
... ... @@ -44,17 +44,19 @@ public class WddPptApi {
44 44 private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION =
45 45 reqParam -> response -> response.bodyToMono(String.class).handle((responseBody, sink) -> {
46 46 HttpRequest request = response.request();
47   - log.error("[wdd-api] 调用失败!请求方式:[{}],请求地址:[{}],请求参数:[{}],响应数据: [{}]",
  47 + log.error("[WenDuoDuoPptApi] 调用失败!请求方式:[{}],请求地址:[{}],请求参数:[{}],响应数据: [{}]",
48 48 request.getMethod(), request.getURI(), reqParam, responseBody);
49   - sink.error(new IllegalStateException("[wdd-api] 调用失败!"));
  49 + sink.error(new IllegalStateException("[WenDuoDuoPptApi] 调用失败!"));
50 50 });
51 51  
52   - // TODO @新:是不是不用 baseUrl 哈
53   - public WddPptApi(String baseUrl) {
  52 + public WenDuoDuoPptApi(String token) {
  53 + Assert.hasText(token, "token 不能为空");
54 54 this.webClient = WebClient.builder()
55   - .baseUrl(baseUrl)
56   - // TODO @新:建议,token 作为 defaultHeader
57   - .defaultHeaders((headers) -> headers.setContentType(MediaType.APPLICATION_JSON))
  55 + .baseUrl(BASE_URL)
  56 + .defaultHeaders((headers) -> {
  57 + headers.setContentType(MediaType.APPLICATION_JSON);
  58 + headers.add(TOKEN_NAME, token);
  59 + })
58 60 .build();
59 61 }
60 62  
... ... @@ -82,37 +84,16 @@ public class WddPptApi {
82 84 .block();
83 85 }
84 86  
85   - // TODO @xin:是不是给个 API 连接,这样 type、content、files 都不用写注释太细了
86 87 /**
87 88 * 创建任务
88 89 *
89 90 * @param type 类型
90   - * 1.智能生成(主题、要求)
91   - * 2.上传文件生成
92   - * 3.上传思维导图生成
93   - * 4.通过word精准转ppt
94   - * 5.通过网页链接生成
95   - * 6.粘贴文本内容生成
96   - * 7.Markdown大纲生成
97 91 * @param content 内容
98   - * type=1 用户输入主题或要求(不超过1000字符)
99   - * type=2、4 不传
100   - * type=3 幕布等分享链接
101   - * type=5 网页链接地址(http/https)
102   - * type=6 粘贴文本内容(不超过20000字符)
103   - * type=7 大纲内容(markdown)
104 92 * @param files 文件列表
105   - * 文件列表(文件数不超过5个,总大小不超过50M):
106   - * type=1 上传参考文件(非必传,支持多个)
107   - * type=2 上传文件(支持多个)
108   - * type=3 上传思维导图(xmind/mm/md)(仅支持一个)
109   - * type=4 上传word文件(仅支持一个)
110   - * type=5、6、7 不传
111   - * <p>
112   - * 支持格式:doc/docx/pdf/ppt/pptx/txt/md/xls/xlsx/csv/html/epub/mobi/xmind/mm
113   - * @return 任务ID
  93 + * @return 任务 ID
  94 + * @see <a href="https://docmee.cn/open-platform/api#%E5%88%9B%E5%BB%BA%E4%BB%BB%E5%8A%A1">创建任务</a>
114 95 */
115   - public ApiResponse createTask(String token, Integer type, String content, List<MultipartFile> files) {
  96 + public ApiResponse createTask(Integer type, String content, List<MultipartFile> files) {
116 97 MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
117 98 formData.add("type", type);
118 99 if (content != null) {
... ... @@ -125,7 +106,6 @@ public class WddPptApi {
125 106 }
126 107 return this.webClient.post()
127 108 .uri("/api/ppt/v2/createTask")
128   - .header("token", token)
129 109 .contentType(MediaType.MULTIPART_FORM_DATA)
130 110 .body(BodyInserters.fromMultipartData(formData))
131 111 .retrieve()
... ... @@ -168,10 +148,9 @@ public class WddPptApi {
168 148 * @param request 请求体
169 149 * @return 模板列表
170 150 */
171   - public PagePptTemplateInfo getTemplatePage(String token, TemplateQueryRequest request) {
  151 + public PagePptTemplateInfo getTemplatePage(TemplateQueryRequest request) {
172 152 return this.webClient.post()
173 153 .uri("/api/ppt/templates")
174   - .header("token", token)
175 154 .bodyValue(request)
176 155 .retrieve()
177 156 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
... ... @@ -185,10 +164,9 @@ public class WddPptApi {
185 164 *
186 165 * @return 大纲内容流
187 166 */
188   - public Flux<Map<String, Object>> createOutline(String token, CreateOutlineRequest request) {
  167 + public Flux<Map<String, Object>> createOutline(CreateOutlineRequest request) {
189 168 return this.webClient.post()
190 169 .uri("/api/ppt/v2/generateContent")
191   - .header("token", token)
192 170 .body(Mono.just(request), CreateOutlineRequest.class)
193 171 .retrieve()
194 172 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
... ... @@ -202,10 +180,9 @@ public class WddPptApi {
202 180 * @param request 请求体
203 181 * @return 大纲内容流
204 182 */
205   - public Flux<Map<String, Object>> updateOutline(String token, UpdateOutlineRequest request) {
  183 + public Flux<Map<String, Object>> updateOutline(UpdateOutlineRequest request) {
206 184 return this.webClient.post()
207 185 .uri("/api/ppt/v2/updateContent")
208   - .header("token", token)
209 186 .body(Mono.just(request), UpdateOutlineRequest.class)
210 187 .retrieve()
211 188 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
... ... @@ -218,11 +195,10 @@ public class WddPptApi {
218 195 *
219 196 * @return PPT信息
220 197 */
221   - public PptInfo create(String token, CreatePptRequest request) {
  198 + public PptInfo create(PptCreateRequest request) {
222 199 return this.webClient.post()
223 200 .uri("/api/ppt/v2/generatePptx")
224   - .header("token", token)
225   - .body(Mono.just(request), CreatePptRequest.class)
  201 + .body(Mono.just(request), PptCreateRequest.class)
226 202 .retrieve()
227 203 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(request))
228 204 .bodyToMono(ApiResponse.class)
... ... @@ -236,7 +212,9 @@ public class WddPptApi {
236 212 .block();
237 213 }
238 214  
239   -
  215 + /**
  216 + * 创建 Token 请求参数
  217 + */
240 218 @JsonInclude(value = JsonInclude.Include.NON_NULL)
241 219 public record CreateTokenRequest(
242 220 String apiKey,
... ... @@ -258,7 +236,8 @@ public class WddPptApi {
258 236 Integer code,
259 237 String message,
260 238 Map<String, Object> data
261   - ) { }
  239 + ) {
  240 + }
262 241  
263 242 /**
264 243 * 创建任务
... ... @@ -268,7 +247,8 @@ public class WddPptApi {
268 247 Integer type,
269 248 String content,
270 249 List<MultipartFile> files
271   - ) { }
  250 + ) {
  251 + }
272 252  
273 253 /**
274 254 * 生成大纲内容请求
... ... @@ -281,7 +261,8 @@ public class WddPptApi {
281 261 String audience,
282 262 String lang,
283 263 String prompt
284   - ) { }
  264 + ) {
  265 + }
285 266  
286 267 /**
287 268 * 修改大纲内容请求
... ... @@ -291,20 +272,23 @@ public class WddPptApi {
291 272 String id,
292 273 String markdown,
293 274 String question
294   - ) { }
  275 + ) {
  276 + }
295 277  
296 278 /**
297   - * 生成 PPT 请求
  279 + * 生成 PPT 请求参数
298 280 */
299   - // TODO @新:要不按照 PptCreateRequest 这样的风格
300 281 @JsonInclude(value = JsonInclude.Include.NON_NULL)
301   - public record CreatePptRequest(
  282 + public record PptCreateRequest(
302 283 String id,
303 284 String templateId,
304 285 String markdown
305   - ) { }
  286 + ) {
  287 + }
306 288  
307   - // TODO @新:要不写下类注释
  289 + /**
  290 + * PPT 信息
  291 + */
308 292 @JsonInclude(value = JsonInclude.Include.NON_NULL)
309 293 public record PptInfo(
310 294 String id,
... ... @@ -323,9 +307,12 @@ public class WddPptApi {
323 307 LocalDateTime createTime,
324 308 String createUser,
325 309 String updateUser
326   - ) { }
  310 + ) {
  311 + }
327 312  
328   - // TODO @新:要不写下类注释
  313 + /**
  314 + * 模板查询请求参数
  315 + */
329 316 @JsonInclude(value = JsonInclude.Include.NON_NULL)
330 317 public record TemplateQueryRequest(
331 318 int page,
... ... @@ -333,25 +320,33 @@ public class WddPptApi {
333 320 Filter filters
334 321 ) {
335 322  
  323 + /**
  324 + * 模板查询过滤条件
  325 + */
336 326 @JsonInclude(value = JsonInclude.Include.NON_NULL)
337 327 public record Filter(
338 328 int type,
339 329 String category,
340 330 String style,
341 331 String themeColor
342   - ) { }
  332 + ) {
  333 + }
343 334  
344 335 }
345 336  
346   - // TODO @新:要不写下类注释
  337 + /**
  338 + * PPT模板分页信息
  339 + */
347 340 @JsonInclude(value = JsonInclude.Include.NON_NULL)
348 341 public record PagePptTemplateInfo(
349 342 List<PptTemplateInfo> data,
350 343 String total
351   - ) {}
352   -
  344 + ) {
  345 + }
353 346  
354   - // TODO @新:要不写下类注释
  347 + /**
  348 + * PPT模板信息
  349 + */
355 350 @JsonInclude(value = JsonInclude.Include.NON_NULL)
356 351 public record PptTemplateInfo(
357 352 String id,
... ... @@ -380,6 +375,7 @@ public class WddPptApi {
380 375 LocalDateTime createTime,
381 376 String createUser,
382 377 String updateUser
383   - ) { }
  378 + ) {
  379 + }
384 380  
385 381 }
386 382 \ No newline at end of file
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/xinghuo/api/XunfeiPptApi.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/model/xinghuo/api/XunFeiPptApi.java
1 1 package cn.iocoder.yudao.framework.ai.core.model.xinghuo.api;
2 2  
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import cn.hutool.crypto.SecureUtil;
  5 +import cn.hutool.crypto.digest.HmacAlgorithm;
3 6 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 7 import com.fasterxml.jackson.annotation.JsonInclude;
  8 +import lombok.Builder;
5 9 import lombok.extern.slf4j.Slf4j;
6 10 import org.springframework.core.io.ByteArrayResource;
7 11 import org.springframework.http.HttpStatusCode;
8 12 import org.springframework.http.MediaType;
9 13 import org.springframework.util.LinkedMultiValueMap;
10 14 import org.springframework.util.MultiValueMap;
  15 +import org.springframework.util.StringUtils;
11 16 import org.springframework.web.multipart.MultipartFile;
12 17 import org.springframework.web.reactive.function.BodyInserters;
13 18 import org.springframework.web.reactive.function.client.ClientResponse;
14 19 import org.springframework.web.reactive.function.client.WebClient;
15 20 import reactor.core.publisher.Mono;
16 21  
17   -import javax.crypto.Mac;
18   -import javax.crypto.spec.SecretKeySpec;
19 22 import java.io.IOException;
20   -import java.nio.charset.StandardCharsets;
21   -import java.security.InvalidKeyException;
22   -import java.security.MessageDigest;
23   -import java.security.NoSuchAlgorithmException;
24   -import java.util.Base64;
25 23 import java.util.HashMap;
26 24 import java.util.List;
27 25 import java.util.Map;
28 26 import java.util.function.Function;
29 27 import java.util.function.Predicate;
30 28  
31   -// TODO @新:要不改成 XunFeiPptApi
32 29 /**
33 30 * 讯飞智能 PPT 生成 API
34 31 *
35   - * @see <a href="https://www.xfyun.cn/doc/spark/PPTv2.html">智能 PPT 生成 API</a>
36   - *
37 32 * @author xiaoxin
  33 + * @see <a href="https://www.xfyun.cn/doc/spark/PPTv2.html">智能 PPT 生成 API</a>
38 34 */
39 35 @Slf4j
40   -public class XunfeiPptApi {
  36 +public class XunFeiPptApi {
41 37  
42 38 public static final String BASE_URL = "https://zwapi.xfyun.cn/api/ppt/v2";
  39 + private static final String HEADER_APP_ID = "appId";
  40 + private static final String HEADER_TIMESTAMP = "timestamp";
  41 + private static final String HEADER_SIGNATURE = "signature";
43 42  
44 43 private final WebClient webClient;
45 44 private final String appId;
... ... @@ -49,18 +48,21 @@ public class XunfeiPptApi {
49 48  
50 49 private final Function<Object, Function<ClientResponse, Mono<? extends Throwable>>> EXCEPTION_FUNCTION =
51 50 reqParam -> response -> response.bodyToMono(String.class).handle((responseBody, sink) -> {
52   - log.error("[xunfei-ppt-api] 调用失败!请求参数:[{}],响应数据: [{}]", reqParam, responseBody);
53   - sink.error(new IllegalStateException("[xunfei-ppt-api] 调用失败!"));
  51 + log.error("[XunFeiPptApi] 调用失败!请求参数:[{}],响应数据: [{}]", reqParam, responseBody);
  52 + sink.error(new IllegalStateException("[XunFeiPptApi] 调用失败!"));
54 53 });
55 54  
56   - // TODO @新:是不是不用 baseUrl 哈
57   - public XunfeiPptApi(String baseUrl, String appId, String apiSecret) {
58   - // TODO @新:建议,增加 defaultheaders,例如说 appid 之类的;或者每个请求,通过 headers customer 处理。
59   - this.webClient = WebClient.builder()
60   - .baseUrl(baseUrl)
61   - .build();
  55 + public XunFeiPptApi(String appId, String apiSecret) {
62 56 this.appId = appId;
63 57 this.apiSecret = apiSecret;
  58 + this.webClient = WebClient.builder()
  59 + .baseUrl(BASE_URL)
  60 + .defaultHeaders((headers) -> {
  61 + headers.setContentType(MediaType.APPLICATION_JSON);
  62 + headers.add(HEADER_APP_ID, appId);
  63 + })
  64 + .build();
  65 +
64 66 }
65 67  
66 68 /**
... ... @@ -72,7 +74,7 @@ public class XunfeiPptApi {
72 74 long timestamp = System.currentTimeMillis() / 1000;
73 75 String ts = String.valueOf(timestamp);
74 76 String signature = generateSignature(appId, apiSecret, timestamp);
75   - return new SignatureInfo(appId, ts, signature);
  77 + return new SignatureInfo(ts, signature);
76 78 }
77 79  
78 80 /**
... ... @@ -84,43 +86,8 @@ public class XunfeiPptApi {
84 86 * @return 签名
85 87 */
86 88 private String generateSignature(String appId, String apiSecret, long timestamp) {
87   - try {
88   - // TODO @新:使用 hutool 简化
89   - String auth = md5(appId + timestamp);
90   - return hmacSHA1Encrypt(auth, apiSecret);
91   - } catch (NoSuchAlgorithmException | InvalidKeyException e) {
92   - log.error("[xunfei-ppt-api] 生成签名失败", e);
93   - throw new IllegalStateException("[xunfei-ppt-api] 生成签名失败");
94   - }
95   - }
96   -
97   - /**
98   - * HMAC SHA1 加密
99   - */
100   - private String hmacSHA1Encrypt(String encryptText, String encryptKey)
101   - throws NoSuchAlgorithmException, InvalidKeyException {
102   - SecretKeySpec keySpec = new SecretKeySpec(
103   - encryptKey.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
104   -
105   - Mac mac = Mac.getInstance("HmacSHA1");
106   - mac.init(keySpec);
107   - byte[] result = mac.doFinal(encryptText.getBytes(StandardCharsets.UTF_8));
108   -
109   - return Base64.getEncoder().encodeToString(result);
110   - }
111   -
112   - /**
113   - * MD5 哈希
114   - */
115   - private String md5(String text) throws NoSuchAlgorithmException {
116   - MessageDigest md = MessageDigest.getInstance("MD5");
117   - byte[] digest = md.digest(text.getBytes(StandardCharsets.UTF_8));
118   -
119   - StringBuilder sb = new StringBuilder();
120   - for (byte b : digest) {
121   - sb.append(String.format("%02x", b));
122   - }
123   - return sb.toString();
  89 + String auth = SecureUtil.md5(appId + timestamp);
  90 + return SecureUtil.hmac(HmacAlgorithm.HmacSHA1, apiSecret).digestBase64(auth, false);
124 91 }
125 92  
126 93 /**
... ... @@ -134,13 +101,11 @@ public class XunfeiPptApi {
134 101 SignatureInfo signInfo = getSignature();
135 102 Map<String, Object> requestBody = new HashMap<>();
136 103 requestBody.put("style", style);
137   - // TODO @新:可以使用 ObjUtil.defaultIfNull
138   - requestBody.put("pageSize", pageSize != null ? pageSize : 10);
  104 + requestBody.put("pageSize", ObjUtil.defaultIfNull(pageSize, 20));
139 105 return this.webClient.post()
140 106 .uri("/template/list")
141   - .header("appId", signInfo.appId)
142   - .header("timestamp", signInfo.timestamp)
143   - .header("signature", signInfo.signature)
  107 + .header(HEADER_TIMESTAMP, signInfo.timestamp)
  108 + .header(HEADER_SIGNATURE, signInfo.signature)
144 109 .contentType(MediaType.APPLICATION_JSON)
145 110 .bodyValue(requestBody)
146 111 .retrieve()
... ... @@ -161,9 +126,8 @@ public class XunfeiPptApi {
161 126 formData.add("query", query);
162 127 return this.webClient.post()
163 128 .uri("/createOutline")
164   - .header("appId", signInfo.appId)
165   - .header("timestamp", signInfo.timestamp)
166   - .header("signature", signInfo.signature)
  129 + .header(HEADER_TIMESTAMP, signInfo.timestamp)
  130 + .header(HEADER_SIGNATURE, signInfo.signature)
167 131 .contentType(MediaType.MULTIPART_FORM_DATA)
168 132 .body(BodyInserters.fromMultipartData(formData))
169 133 .retrieve()
... ... @@ -207,12 +171,11 @@ public class XunfeiPptApi {
207 171 */
208 172 public CreateResponse create(CreatePptRequest request) {
209 173 SignatureInfo signInfo = getSignature();
210   - MultiValueMap<String, Object> formData = buildCreateFormData(request);
  174 + MultiValueMap<String, Object> formData = buildCreatePptFormData(request);
211 175 return this.webClient.post()
212 176 .uri("/create")
213   - .header("appId", signInfo.appId)
214   - .header("timestamp", signInfo.timestamp)
215   - .header("signature", signInfo.signature)
  177 + .header(HEADER_TIMESTAMP, signInfo.timestamp)
  178 + .header(HEADER_SIGNATURE, signInfo.signature)
216 179 .contentType(MediaType.MULTIPART_FORM_DATA)
217 180 .body(BodyInserters.fromMultipartData(formData))
218 181 .retrieve()
... ... @@ -247,9 +210,8 @@ public class XunfeiPptApi {
247 210 SignatureInfo signInfo = getSignature();
248 211 return this.webClient.post()
249 212 .uri("/createPptByOutline")
250   - .header("appId", signInfo.appId)
251   - .header("timestamp", signInfo.timestamp)
252   - .header("signature", signInfo.signature)
  213 + .header(HEADER_TIMESTAMP, signInfo.timestamp)
  214 + .header(HEADER_SIGNATURE, signInfo.signature)
253 215 .contentType(MediaType.APPLICATION_JSON)
254 216 .bodyValue(request)
255 217 .retrieve()
... ... @@ -271,9 +233,8 @@ public class XunfeiPptApi {
271 233 .path("/progress")
272 234 .queryParam("sid", sid)
273 235 .build())
274   - .header("appId", signInfo.appId)
275   - .header("timestamp", signInfo.timestamp)
276   - .header("signature", signInfo.signature)
  236 + .header(HEADER_TIMESTAMP, signInfo.timestamp)
  237 + .header(HEADER_SIGNATURE, signInfo.signature)
277 238 .retrieve()
278 239 .onStatus(STATUS_PREDICATE, EXCEPTION_FUNCTION.apply(sid))
279 240 .bodyToMono(ProgressResponse.class)
... ... @@ -285,10 +246,10 @@ public class XunfeiPptApi {
285 246 */
286 247 @JsonInclude(value = JsonInclude.Include.NON_NULL)
287 248 private record SignatureInfo(
288   - String appId,
289 249 String timestamp,
290 250 String signature
291   - ) { }
  251 + ) {
  252 + }
292 253  
293 254 /**
294 255 * 模板列表响应
... ... @@ -300,7 +261,8 @@ public class XunfeiPptApi {
300 261 String desc,
301 262 Integer count,
302 263 TemplatePageData data
303   - ) { }
  264 + ) {
  265 + }
304 266  
305 267 /**
306 268 * 模板列表数据
... ... @@ -310,7 +272,8 @@ public class XunfeiPptApi {
310 272 String total,
311 273 List<TemplateInfo> records,
312 274 Integer pageNum
313   - ) { }
  275 + ) {
  276 + }
314 277  
315 278 /**
316 279 * 模板信息
... ... @@ -324,7 +287,8 @@ public class XunfeiPptApi {
324 287 String industry,
325 288 String style,
326 289 String detailImage
327   - ) { }
  290 + ) {
  291 + }
328 292  
329 293 /**
330 294 * 创建响应
... ... @@ -336,7 +300,8 @@ public class XunfeiPptApi {
336 300 String desc,
337 301 Integer count,
338 302 CreateResponseData data
339   - ) { }
  303 + ) {
  304 + }
340 305  
341 306 /**
342 307 * 创建响应数据
... ... @@ -348,7 +313,8 @@ public class XunfeiPptApi {
348 313 String title,
349 314 String subTitle,
350 315 OutlineData outline
351   - ) { }
  316 + ) {
  317 + }
352 318  
353 319 /**
354 320 * 大纲数据结构
... ... @@ -375,7 +341,8 @@ public class XunfeiPptApi {
375 341 @JsonInclude(value = JsonInclude.Include.NON_NULL)
376 342 public record ChapterContent(
377 343 String chapterTitle
378   - ) { }
  344 + ) {
  345 + }
379 346  
380 347 }
381 348  
... ... @@ -397,7 +364,8 @@ public class XunfeiPptApi {
397 364 int code,
398 365 String desc,
399 366 ProgressResponseData data
400   - ) { }
  367 + ) {
  368 + }
401 369  
402 370 /**
403 371 * 进度响应数据
... ... @@ -407,13 +375,12 @@ public class XunfeiPptApi {
407 375 int process,
408 376 String pptId,
409 377 String pptUrl,
410   - // TODO @新:字段注释,去掉
411   - String pptStatus, // PPT构建状态:building(构建中),done(已完成),build_failed(生成失败)
412   - String aiImageStatus, // ai配图状态:building(构建中),done(已完成)
413   - String cardNoteStatus, // 演讲备注状态:building(构建中),done(已完成)
414   - String errMsg, // 生成PPT的失败信息
415   - Integer totalPages, // 生成PPT的总页数
416   - Integer donePages // 生成PPT的完成页数
  378 + String pptStatus,
  379 + String aiImageStatus,
  380 + String cardNoteStatus,
  381 + String errMsg,
  382 + Integer totalPages,
  383 + Integer donePages
417 384 ) {
418 385  
419 386 /**
... ... @@ -454,6 +421,7 @@ public class XunfeiPptApi {
454 421 * 通过大纲创建 PPT 请求参数
455 422 */
456 423 @JsonInclude(value = JsonInclude.Include.NON_NULL)
  424 + @Builder
457 425 public record CreatePptByOutlineRequest(
458 426 String query, // 用户生成PPT要求(最多8000字)
459 427 String outlineSid, // 已生成大纲后,响应返回的请求大纲唯一id
... ... @@ -469,122 +437,17 @@ public class XunfeiPptApi {
469 437 Boolean isFigure, // 是否自动配图
470 438 String aiImage // ai配图类型:normal、advanced
471 439 ) {
472   -
473   - /**
474   - * 创建构建器
475   - *
476   - * @return 构建器
477   - */
478   - public static Builder builder() {
479   - return new Builder();
480   - }
481   -
482   - // TODO @新:这个可以用 lombok 简化么?
483   - /**
484   - * 构建器类
485   - */
486   - public static class Builder {
487   -
488   - private String query;
489   - private String outlineSid;
490   - private OutlineData outline;
491   - private String templateId;
492   - private String businessId;
493   - private String author;
494   - private Boolean isCardNote;
495   - private Boolean search;
496   - private String language;
497   - private String fileUrl;
498   - private String fileName;
499   - private Boolean isFigure;
500   - private String aiImage;
501   -
502   - public Builder query(String query) {
503   - this.query = query;
504   - return this;
505   - }
506   -
507   - public Builder outlineSid(String outlineSid) {
508   - this.outlineSid = outlineSid;
509   - return this;
510   - }
511   -
512   - public Builder outline(OutlineData outline) {
513   - this.outline = outline;
514   - return this;
515   - }
516   -
517   - public Builder templateId(String templateId) {
518   - this.templateId = templateId;
519   - return this;
520   - }
521   -
522   - public Builder businessId(String businessId) {
523   - this.businessId = businessId;
524   - return this;
525   - }
526   -
527   - public Builder author(String author) {
528   - this.author = author;
529   - return this;
530   - }
531   -
532   - public Builder isCardNote(Boolean isCardNote) {
533   - this.isCardNote = isCardNote;
534   - return this;
535   - }
536   -
537   - public Builder search(Boolean search) {
538   - this.search = search;
539   - return this;
540   - }
541   -
542   - public Builder language(String language) {
543   - this.language = language;
544   - return this;
545   - }
546   -
547   - public Builder fileUrl(String fileUrl) {
548   - this.fileUrl = fileUrl;
549   - return this;
550   - }
551   -
552   - public Builder fileName(String fileName) {
553   - this.fileName = fileName;
554   - return this;
555   - }
556   -
557   - public Builder isFigure(Boolean isFigure) {
558   - this.isFigure = isFigure;
559   - return this;
560   - }
561   -
562   - public Builder aiImage(String aiImage) {
563   - this.aiImage = aiImage;
564   - return this;
565   - }
566   -
567   - public CreatePptByOutlineRequest build() {
568   - return new CreatePptByOutlineRequest(
569   - query, outlineSid, outline, templateId, businessId, author,
570   - isCardNote, search, language, fileUrl, fileName, isFigure, aiImage
571   - );
572   - }
573   - }
574 440 }
575 441  
  442 +
576 443 /**
577 444 * 构建创建 PPT 的表单数据
578 445 *
579 446 * @param request 请求参数
580 447 * @return 表单数据
581 448 */
582   - private MultiValueMap<String, Object> buildCreateFormData(CreatePptRequest request) {
  449 + private MultiValueMap<String, Object> buildCreatePptFormData(CreatePptRequest request) {
583 450 MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
584   - // 添加请求参数
585   - if (request.query() != null) {
586   - formData.add("query", request.query());
587   - }
588 451 if (request.file() != null) {
589 452 try {
590 453 formData.add("file", new ByteArrayResource(request.file().getBytes()) {
... ... @@ -594,48 +457,51 @@ public class XunfeiPptApi {
594 457 }
595 458 });
596 459 } catch (IOException e) {
597   - log.error("[xunfei-ppt-api] 文件处理失败", e);
598   - throw new IllegalStateException("[xunfei-ppt-api] 文件处理失败", e);
  460 + log.error("[XunFeiPptApi] 文件处理失败", e);
  461 + throw new IllegalStateException("[XunFeiPptApi] 文件处理失败", e);
599 462 }
600 463 }
601   - // TODO @新:要不搞个 MapUtil.addIfPresent 方法?
602   - if (request.fileUrl() != null) {
603   - formData.add("fileUrl", request.fileUrl());
604   - }
605   - if (request.fileName() != null) {
606   - formData.add("fileName", request.fileName());
607   - }
608   - if (request.templateId() != null) {
609   - formData.add("templateId", request.templateId());
610   - }
611   - if (request.businessId() != null) {
612   - formData.add("businessId", request.businessId());
613   - }
614   - if (request.author() != null) {
615   - formData.add("author", request.author());
616   - }
617   - if (request.isCardNote() != null) {
618   - formData.add("isCardNote", request.isCardNote().toString());
619   - }
620   - if (request.search() != null) {
621   - formData.add("search", request.search().toString());
622   - }
623   - if (request.language() != null) {
624   - formData.add("language", request.language());
  464 + Map<String, Object> param = new HashMap<>();
  465 + addIfPresent(param, "query", request.query());
  466 + addIfPresent(param, "fileUrl", request.fileUrl());
  467 + addIfPresent(param, "fileName", request.fileName());
  468 + addIfPresent(param, "templateId", request.templateId());
  469 + addIfPresent(param, "businessId", request.businessId());
  470 + addIfPresent(param, "author", request.author());
  471 + addIfPresent(param, "isCardNote", request.isCardNote());
  472 + addIfPresent(param, "search", request.search());
  473 + addIfPresent(param, "language", request.language());
  474 + addIfPresent(param, "isFigure", request.isFigure());
  475 + addIfPresent(param, "aiImage", request.aiImage());
  476 + param.forEach(formData::add);
  477 + return formData;
  478 + }
  479 +
  480 + public static <K, V> void addIfPresent(Map<K, V> map, K key, V value) {
  481 + if (ObjUtil.isNull(key) || ObjUtil.isNull(map)) {
  482 + return;
625 483 }
626   - if (request.isFigure() != null) {
627   - formData.add("isFigure", request.isFigure().toString());
  484 +
  485 + boolean isPresent = false;
  486 + if (ObjUtil.isNotNull(value)) {
  487 + if (value instanceof String) {
  488 + // 字符串:需要有实际内容
  489 + isPresent = StringUtils.hasText((String) value);
  490 + } else {
  491 + // 其他类型:非 null 即视为存在
  492 + isPresent = true;
  493 + }
628 494 }
629   - if (request.aiImage() != null) {
630   - formData.add("aiImage", request.aiImage());
  495 + if (isPresent) {
  496 + map.put(key, value);
631 497 }
632   - return formData;
633 498 }
634 499  
635 500 /**
636 501 * 直接生成PPT请求参数
637 502 */
638 503 @JsonInclude(value = JsonInclude.Include.NON_NULL)
  504 + @Builder
639 505 public record CreatePptRequest(
640 506 String query, // 用户生成PPT要求(最多8000字)
641 507 MultipartFile file, // 上传文件
... ... @@ -651,109 +517,6 @@ public class XunfeiPptApi {
651 517 String aiImage // ai配图类型:normal、advanced
652 518 ) {
653 519  
654   - /**
655   - * 创建构建器
656   - *
657   - * @return 构建器
658   - */
659   - public static Builder builder() {
660   - return new Builder();
661   - }
662   -
663   - /**
664   - * 构建器类
665   - */
666   - public static class Builder {
667   -
668   - private String query;
669   - private MultipartFile file;
670   - private String fileUrl;
671   - private String fileName;
672   - private String templateId;
673   - private String businessId;
674   - private String author;
675   - private Boolean isCardNote;
676   - private Boolean search;
677   - private String language;
678   - private Boolean isFigure;
679   - private String aiImage;
680   -
681   - // TODO @新:这个可以用 lombok 简化么?
682   -
683   - public Builder query(String query) {
684   - this.query = query;
685   - return this;
686   - }
687   -
688   - public Builder file(MultipartFile file) {
689   - this.file = file;
690   - return this;
691   - }
692   -
693   - public Builder fileUrl(String fileUrl) {
694   - this.fileUrl = fileUrl;
695   - return this;
696   - }
697   -
698   - public Builder fileName(String fileName) {
699   - this.fileName = fileName;
700   - return this;
701   - }
702   -
703   - public Builder templateId(String templateId) {
704   - this.templateId = templateId;
705   - return this;
706   - }
707   -
708   - public Builder businessId(String businessId) {
709   - this.businessId = businessId;
710   - return this;
711   - }
712   -
713   - public Builder author(String author) {
714   - this.author = author;
715   - return this;
716   - }
717   -
718   - public Builder isCardNote(Boolean isCardNote) {
719   - this.isCardNote = isCardNote;
720   - return this;
721   - }
722   -
723   - public Builder search(Boolean search) {
724   - this.search = search;
725   - return this;
726   - }
727   -
728   - public Builder language(String language) {
729   - this.language = language;
730   - return this;
731   - }
732   -
733   - public Builder isFigure(Boolean isFigure) {
734   - this.isFigure = isFigure;
735   - return this;
736   - }
737   -
738   - public Builder aiImage(String aiImage) {
739   - this.aiImage = aiImage;
740   - return this;
741   - }
742   -
743   - public CreatePptRequest build() {
744   - // 验证参数
745   - if (query == null && file == null && fileUrl == null) {
746   - throw new IllegalArgumentException("query、file、fileUrl必填其一");
747   - }
748   - if ((file != null || fileUrl != null) && fileName == null) {
749   - throw new IllegalArgumentException("如果传file或者fileUrl,fileName必填");
750   - }
751   - return new CreatePptRequest(
752   - query, file, fileUrl, fileName, templateId, businessId, author,
753   - isCardNote, search, language, isFigure, aiImage
754   - );
755   - }
756   - }
757 520 }
758 521  
759 522 }
760 523 \ No newline at end of file
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/mcp/DouBaoMcpTests.java 0 → 100644
  1 +package cn.iocoder.yudao.framework.ai.mcp;
  2 +
  3 +import cn.iocoder.yudao.framework.ai.core.model.doubao.DouBaoChatModel;
  4 +import org.junit.jupiter.api.Test;
  5 +import org.springframework.ai.chat.client.ChatClient;
  6 +import org.springframework.ai.openai.OpenAiChatModel;
  7 +import org.springframework.ai.openai.OpenAiChatOptions;
  8 +import org.springframework.ai.openai.api.OpenAiApi;
  9 +import org.springframework.ai.tool.annotation.Tool;
  10 +import org.springframework.ai.tool.method.MethodToolCallbackProvider;
  11 +
  12 +public class DouBaoMcpTests {
  13 +
  14 + private final OpenAiChatModel openAiChatModel = OpenAiChatModel.builder()
  15 + .openAiApi(OpenAiApi.builder()
  16 + .baseUrl(DouBaoChatModel.BASE_URL)
  17 + .apiKey("5c1b5747-26d2-4ebd-a4e0-dd0e8d8b4272") // apiKey
  18 + .build())
  19 + .defaultOptions(OpenAiChatOptions.builder()
  20 + .model("doubao-1-5-lite-32k-250115") // 模型(doubao)
  21 + .temperature(0.7)
  22 + .build())
  23 + .build();
  24 +
  25 + private final DouBaoChatModel chatModel = new DouBaoChatModel(openAiChatModel);
  26 +
  27 + private final MethodToolCallbackProvider provider = MethodToolCallbackProvider.builder()
  28 + .toolObjects(new UserService())
  29 + .build();
  30 +
  31 + private final ChatClient chatClient = ChatClient.builder(chatModel)
  32 + .defaultTools(provider)
  33 + .build();
  34 +
  35 + @Test
  36 + public void testMcpGetUserInfo() {
  37 +
  38 + // 打印结果
  39 + System.out.println(chatClient.prompt()
  40 + .user("目前有哪些工具可以使用")
  41 + .call()
  42 + .content());
  43 + System.out.println("====================================");
  44 + // 打印结果
  45 + System.out.println(chatClient.prompt()
  46 + .user("小新的年龄是多少")
  47 + .call()
  48 + .content());
  49 + System.out.println("====================================");
  50 + // 打印结果
  51 + System.out.println(chatClient.prompt()
  52 + .user("获取小新的基本信息")
  53 + .call()
  54 + .content());
  55 + System.out.println("====================================");
  56 + // 打印结果
  57 + System.out.println(chatClient.prompt()
  58 + .user("小新是什么职业的")
  59 + .call()
  60 + .content());
  61 + System.out.println("====================================");
  62 + // 打印结果
  63 + System.out.println(chatClient.prompt()
  64 + .user("小新的教育背景")
  65 + .call()
  66 + .content());
  67 + System.out.println("====================================");
  68 + // 打印结果
  69 + System.out.println(chatClient.prompt()
  70 + .user("小新的兴趣爱好是什么")
  71 + .call()
  72 + .content());
  73 + System.out.println("====================================");
  74 +
  75 + }
  76 +
  77 +
  78 + static class UserService {
  79 +
  80 + @Tool(name = "getUserAge", description = "获取用户年龄")
  81 + public String getUserAge(String userName) {
  82 + return "《" + userName + "》的年龄为:18";
  83 + }
  84 +
  85 + @Tool(name = "getUserSex", description = "获取用户性别")
  86 + public String getUserSex(String userName) {
  87 + return "《" + userName + "》的性别为:男";
  88 + }
  89 +
  90 + @Tool(name = "getUserBasicInfo", description = "获取用户基本信息,包括姓名、年龄、性别等")
  91 + public String getUserBasicInfo(String userName) {
  92 + return "《" + userName + "》的基本信息:\n姓名:" + userName + "\n年龄:18\n性别:男\n身高:175cm\n体重:65kg";
  93 + }
  94 +
  95 + @Tool(name = "getUserContact", description = "获取用户联系方式,包括电话、邮箱等")
  96 + public String getUserContact(String userName) {
  97 + return "《" + userName + "》的联系方式:\n电话:138****1234\n邮箱:" + userName.toLowerCase() + "@example.com\nQQ:123456789";
  98 + }
  99 +
  100 + @Tool(name = "getUserAddress", description = "获取用户地址信息")
  101 + public String getUserAddress(String userName) {
  102 + return "《" + userName + "》的地址信息:北京市朝阳区科技园区88号";
  103 + }
  104 +
  105 + @Tool(name = "getUserJob", description = "获取用户职业信息")
  106 + public String getUserJob(String userName) {
  107 + return "《" + userName + "》的职业信息:软件工程师,就职于ABC科技有限公司,工作年限5年";
  108 + }
  109 +
  110 + @Tool(name = "getUserHobbies", description = "获取用户兴趣爱好")
  111 + public String getUserHobbies(String userName) {
  112 + return "《" + userName + "》的兴趣爱好:编程、阅读、旅游、摄影、打篮球";
  113 + }
  114 +
  115 + @Tool(name = "getUserEducation", description = "获取用户教育背景")
  116 + public String getUserEducation(String userName) {
  117 + return "《" + userName + "》的教育背景:\n本科:计算机科学与技术专业,北京大学\n硕士:软件工程专业,清华大学";
  118 + }
  119 +
  120 + }
  121 +
  122 +}
0 123 \ No newline at end of file
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/ppt/wdd/WddPptApiTests.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/ppt/wdd/WenDuoDuoPptApiTests.java
1 1 package cn.iocoder.yudao.framework.ai.ppt.wdd;
2 2  
3   -import cn.iocoder.yudao.framework.ai.core.model.wenduoduo.api.WddPptApi;
  3 +import cn.iocoder.yudao.framework.ai.core.model.wenduoduo.api.WenDuoDuoPptApi;
4 4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5 5 import org.junit.jupiter.api.Disabled;
6 6 import org.junit.jupiter.api.Test;
... ... @@ -10,24 +10,23 @@ import java.util.Map;
10 10 import java.util.Objects;
11 11  
12 12 /**
13   - * {@link WddPptApi} 集成测试
  13 + * {@link WenDuoDuoPptApi} 集成测试
14 14 *
15 15 * @author xiaoxin
16 16 */
17   -public class WddPptApiTests {
18   -
19   - private final WddPptApi wddPptApi = new WddPptApi("https://docmee.cn");
  17 +public class WenDuoDuoPptApiTests {
20 18  
21 19 private final String token = ""; // API Token
  20 + private final WenDuoDuoPptApi wenDuoDuoPptApi = new WenDuoDuoPptApi(token);
22 21  
23 22 @Test
24 23 @Disabled
25 24 public void testCreateApiToken() {
26 25 // 准备参数
27 26 String apiKey = "";
28   - WddPptApi.CreateTokenRequest request = new WddPptApi.CreateTokenRequest(apiKey);
  27 + WenDuoDuoPptApi.CreateTokenRequest request = new WenDuoDuoPptApi.CreateTokenRequest(apiKey);
29 28 // 调用方法
30   - String token = wddPptApi.createApiToken(request);
  29 + String token = wenDuoDuoPptApi.createApiToken(request);
31 30 // 打印结果
32 31 System.out.println(token);
33 32 }
... ... @@ -38,7 +37,7 @@ public class WddPptApiTests {
38 37 @Test
39 38 @Disabled
40 39 public void testCreateTask() {
41   - WddPptApi.ApiResponse apiResponse = wddPptApi.createTask(token, 1, "dify 介绍", null);
  40 + WenDuoDuoPptApi.ApiResponse apiResponse = wenDuoDuoPptApi.createTask(1, "dify 介绍", null);
42 41 System.out.println(apiResponse);
43 42 }
44 43  
... ... @@ -46,10 +45,10 @@ public class WddPptApiTests {
46 45 @Test // 创建大纲
47 46 @Disabled
48 47 public void testGenerateOutlineRequest() {
49   - WddPptApi.CreateOutlineRequest request = new WddPptApi.CreateOutlineRequest(
  48 + WenDuoDuoPptApi.CreateOutlineRequest request = new WenDuoDuoPptApi.CreateOutlineRequest(
50 49 "1901539019628613632", "medium", null, null, null, null);
51 50 // 调用
52   - Flux<Map<String, Object>> flux = wddPptApi.createOutline(token, request);
  51 + Flux<Map<String, Object>> flux = wenDuoDuoPptApi.createOutline(request);
53 52 StringBuffer contentBuffer = new StringBuffer();
54 53 flux.doOnNext(chunk -> {
55 54 contentBuffer.append(chunk.get("text"));
... ... @@ -69,10 +68,10 @@ public class WddPptApiTests {
69 68 @Test
70 69 @Disabled
71 70 public void testUpdateOutlineRequest() {
72   - WddPptApi.UpdateOutlineRequest request = new WddPptApi.UpdateOutlineRequest(
  71 + WenDuoDuoPptApi.UpdateOutlineRequest request = new WenDuoDuoPptApi.UpdateOutlineRequest(
73 72 "1901539019628613632", TEST_OUT_LINE_CONTENT, "精简一点,三个章节即可");
74 73 // 调用
75   - Flux<Map<String, Object>> flux = wddPptApi.updateOutline(token, request);
  74 + Flux<Map<String, Object>> flux = wenDuoDuoPptApi.updateOutline(request);
76 75 StringBuffer contentBuffer = new StringBuffer();
77 76 flux.doOnNext(chunk -> {
78 77 contentBuffer.append(chunk.get("text"));
... ... @@ -94,11 +93,11 @@ public class WddPptApiTests {
94 93 @Disabled
95 94 public void testGetPptTemplatePage() {
96 95 // 准备参数
97   - WddPptApi.TemplateQueryRequest.Filter filter = new WddPptApi.TemplateQueryRequest.Filter(
  96 + WenDuoDuoPptApi.TemplateQueryRequest.Filter filter = new WenDuoDuoPptApi.TemplateQueryRequest.Filter(
98 97 1, null, null, null);
99   - WddPptApi.TemplateQueryRequest request = new WddPptApi.TemplateQueryRequest(1, 10, filter);
  98 + WenDuoDuoPptApi.TemplateQueryRequest request = new WenDuoDuoPptApi.TemplateQueryRequest(1, 10, filter);
100 99 // 调用
101   - WddPptApi.PagePptTemplateInfo pptTemplatePage = wddPptApi.getTemplatePage(token, request);
  100 + WenDuoDuoPptApi.PagePptTemplateInfo pptTemplatePage = wenDuoDuoPptApi.getTemplatePage(request);
102 101 // 打印结果
103 102 System.out.println(pptTemplatePage);
104 103 }
... ... @@ -110,9 +109,9 @@ public class WddPptApiTests {
110 109 @Disabled
111 110 public void testGeneratePptx() {
112 111 // 准备参数
113   - WddPptApi.CreatePptRequest request = new WddPptApi.CreatePptRequest("1901539019628613632", "1805081814809960448", TEST_OUT_LINE_CONTENT);
  112 + WenDuoDuoPptApi.PptCreateRequest request = new WenDuoDuoPptApi.PptCreateRequest("1901539019628613632", "1805081814809960448", TEST_OUT_LINE_CONTENT);
114 113 // 调用
115   - WddPptApi.PptInfo pptInfo = wddPptApi.create(token, request);
  114 + WenDuoDuoPptApi.PptInfo pptInfo = wenDuoDuoPptApi.create(request);
116 115 // 打印结果
117 116 System.out.println(pptInfo);
118 117 }
... ... @@ -309,6 +308,7 @@ public class WddPptApiTests {
309 308 #### 7.2.2 合作共赢
310 309 期待与更多的企业和机构合作,共同推动AI技术的应用。
311 310 #### 7.2.3 共创未来
312   - 让我们一起用AI技术改变世界,共创美好未来。""";
  311 + 让我们一起用AI技术改变世界,共创美好未来。
  312 + """;
313 313  
314 314 }
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/ppt/xunfei/XunfeiPptApiTests.java renamed to yudao-module-ai/yudao-spring-boot-starter-ai/src/test/java/cn/iocoder/yudao/framework/ai/ppt/xunfei/XunFeiPptApiTests.java
1 1 package cn.iocoder.yudao.framework.ai.ppt.xunfei;
2 2  
3 3 import cn.hutool.core.io.FileUtil;
4   -import cn.iocoder.yudao.framework.ai.core.model.xinghuo.api.XunfeiPptApi;
  4 +import cn.iocoder.yudao.framework.ai.core.model.xinghuo.api.XunFeiPptApi;
5 5 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
6 6 import org.junit.jupiter.api.Disabled;
7 7 import org.junit.jupiter.api.Test;
... ... @@ -11,17 +11,17 @@ import org.springframework.web.multipart.MultipartFile;
11 11 import java.io.File;
12 12  
13 13 /**
14   - * {@link XunfeiPptApi} 集成测试
  14 + * {@link XunFeiPptApi} 集成测试
15 15 *
16 16 * @author xiaoxin
17 17 */
18   -public class XunfeiPptApiTests {
  18 +public class XunFeiPptApiTests {
19 19  
20 20 // 讯飞 API 配置信息,实际使用时请替换为您的应用信息
21   - private static final String APP_ID = "";
22   - private static final String API_SECRET = "";
  21 + private static final String APP_ID = "6c8ac023";
  22 + private static final String API_SECRET = "Y2RjM2Q1MWJjZTdkYmFiODc0OGE5NmRk";
23 23  
24   - private final XunfeiPptApi xunfeiPptApi = new XunfeiPptApi(XunfeiPptApi.BASE_URL, APP_ID, API_SECRET);
  24 + private final XunFeiPptApi xunfeiPptApi = new XunFeiPptApi(APP_ID, API_SECRET);
25 25  
26 26 /**
27 27 * 获取 PPT 模板列表
... ... @@ -30,7 +30,7 @@ public class XunfeiPptApiTests {
30 30 @Disabled
31 31 public void testGetTemplatePage() {
32 32 // 调用方法
33   - XunfeiPptApi.TemplatePageResponse response = xunfeiPptApi.getTemplatePage("商务", 10);
  33 + XunFeiPptApi.TemplatePageResponse response = xunfeiPptApi.getTemplatePage("商务", 10);
34 34 // 打印结果
35 35 System.out.println("模板列表响应:" + JsonUtils.toJsonString(response));
36 36  
... ... @@ -41,7 +41,7 @@ public class XunfeiPptApiTests {
41 41  
42 42 // 打印第一个模板的信息(如果存在)
43 43 if (!response.data().records().isEmpty()) {
44   - XunfeiPptApi.TemplateInfo firstTemplate = response.data().records().get(0);
  44 + XunFeiPptApi.TemplateInfo firstTemplate = response.data().records().get(0);
45 45 System.out.println("模板ID:" + firstTemplate.templateIndexId());
46 46 System.out.println("模板风格:" + firstTemplate.style());
47 47 System.out.println("模板颜色:" + firstTemplate.color());
... ... @@ -56,7 +56,7 @@ public class XunfeiPptApiTests {
56 56 @Test
57 57 @Disabled
58 58 public void testCreateOutline() {
59   - XunfeiPptApi.CreateResponse response = getCreateResponse();
  59 + XunFeiPptApi.CreateResponse response = getCreateResponse();
60 60 // 打印结果
61 61 System.out.println("创建大纲响应:" + JsonUtils.toJsonString(response));
62 62  
... ... @@ -75,9 +75,10 @@ public class XunfeiPptApiTests {
75 75  
76 76 /**
77 77 * 创建大纲(通过文本)
  78 + *
78 79 * @return 创建大纲响应
79 80 */
80   - private XunfeiPptApi.CreateResponse getCreateResponse() {
  81 + private XunFeiPptApi.CreateResponse getCreateResponse() {
81 82 String param = "智能体平台 Dify 介绍";
82 83 return xunfeiPptApi.createOutline(param);
83 84 }
... ... @@ -89,9 +90,9 @@ public class XunfeiPptApiTests {
89 90 @Disabled
90 91 public void testCreatePptByOutlineWithFullParams() {
91 92 // 创建大纲对象
92   - XunfeiPptApi.CreateResponse createResponse = getCreateResponse();
  93 + XunFeiPptApi.CreateResponse createResponse = getCreateResponse();
93 94 // 调用方法
94   - XunfeiPptApi.CreateResponse response = xunfeiPptApi.createPptByOutline(createResponse.data().outline(), "精简一些,不要超过6个章节");
  95 + XunFeiPptApi.CreateResponse response = xunfeiPptApi.createPptByOutline(createResponse.data().outline(), "精简一些,不要超过6个章节");
95 96 // 打印结果
96 97 System.out.println("通过大纲创建 PPT 响应:" + JsonUtils.toJsonString(response));
97 98  
... ... @@ -114,13 +115,13 @@ public class XunfeiPptApiTests {
114 115 String sid = "e96dac09f2ec4ee289f029a5fb874ecd"; // 替换为实际的sid
115 116  
116 117 // 调用方法
117   - XunfeiPptApi.ProgressResponse response = xunfeiPptApi.checkProgress(sid);
  118 + XunFeiPptApi.ProgressResponse response = xunfeiPptApi.checkProgress(sid);
118 119 // 打印结果
119 120 System.out.println("检查进度响应:" + JsonUtils.toJsonString(response));
120 121  
121 122 // 安全地访问响应数据
122 123 if (response != null && response.data() != null) {
123   - XunfeiPptApi.ProgressResponseData data = response.data();
  124 + XunFeiPptApi.ProgressResponseData data = response.data();
124 125  
125 126 // 打印PPT生成状态
126 127 System.out.println("PPT 构建状态: " + data.pptStatus());
... ... @@ -160,7 +161,7 @@ public class XunfeiPptApiTests {
160 161 @Disabled
161 162 public void testPollCheckProgress() throws InterruptedException {
162 163 // 准备参数 - 使用之前创建 PP T时返回的 sid
163   - String sid = "fa36e926f2ed434987fcb4c1f0776ffb"; // 替换为实际的sid
  164 + String sid = "1690ef6ee0344e72b5c5434f403b8eaa"; // 替换为实际的sid
164 165  
165 166 // 最大轮询次数
166 167 int maxPolls = 20;
... ... @@ -171,11 +172,11 @@ public class XunfeiPptApiTests {
171 172 System.out.println("第" + (i + 1) + "次查询进度...");
172 173  
173 174 // 调用方法
174   - XunfeiPptApi.ProgressResponse response = xunfeiPptApi.checkProgress(sid);
  175 + XunFeiPptApi.ProgressResponse response = xunfeiPptApi.checkProgress(sid);
175 176  
176 177 // 安全地访问响应数据
177 178 if (response != null && response.data() != null) {
178   - XunfeiPptApi.ProgressResponseData data = response.data();
  179 + XunFeiPptApi.ProgressResponseData data = response.data();
179 180  
180 181 // 打印进度信息
181 182 System.out.println("PPT 构建状态: " + data.pptStatus());
... ... @@ -218,7 +219,7 @@ public class XunfeiPptApiTests {
218 219 String query = "合肥天气趋势分析,包括近5年的气温变化、降水量变化、极端天气事件,以及对城市生活的影响";
219 220  
220 221 // 调用方法
221   - XunfeiPptApi.CreateResponse response = xunfeiPptApi.create(query);
  222 + XunFeiPptApi.CreateResponse response = xunfeiPptApi.create(query);
222 223 // 打印结果
223 224 System.out.println("直接创建 PPT 响应:" + JsonUtils.toJsonString(response));
224 225  
... ... @@ -244,7 +245,7 @@ public class XunfeiPptApiTests {
244 245 MultipartFile multipartFile = convertFileToMultipartFile(file);
245 246  
246 247 // 调用方法
247   - XunfeiPptApi.CreateResponse response = xunfeiPptApi.create(multipartFile, file.getName());
  248 + XunFeiPptApi.CreateResponse response = xunfeiPptApi.create(multipartFile, file.getName());
248 249 // 打印结果
249 250 System.out.println("通过文件创建PPT响应:" + JsonUtils.toJsonString(response));
250 251  
... ... @@ -269,7 +270,7 @@ public class XunfeiPptApiTests {
269 270 String query = "合肥天气趋势分析,包括近 5 年的气温变化、降水量变化、极端天气事件,以及对城市生活的影响";
270 271  
271 272 // 创建请求对象
272   - XunfeiPptApi.CreatePptRequest request = XunfeiPptApi.CreatePptRequest.builder()
  273 + XunFeiPptApi.CreatePptRequest request = XunFeiPptApi.CreatePptRequest.builder()
273 274 .query(query)
274 275 .language("cn")
275 276 .isCardNote(true)
... ... @@ -280,7 +281,7 @@ public class XunfeiPptApiTests {
280 281 .build();
281 282  
282 283 // 调用方法
283   - XunfeiPptApi.CreateResponse response = xunfeiPptApi.create(request);
  284 + XunFeiPptApi.CreateResponse response = xunfeiPptApi.create(request);
284 285 // 打印结果
285 286 System.out.println("使用完整参数创建 PPT 响应:" + JsonUtils.toJsonString(response));
286 287  
... ... @@ -296,9 +297,9 @@ public class XunfeiPptApiTests {
296 297  
297 298 // 立即查询一次进度
298 299 System.out.println("立即查询进度...");
299   - XunfeiPptApi.ProgressResponse progressResponse = xunfeiPptApi.checkProgress(sid);
  300 + XunFeiPptApi.ProgressResponse progressResponse = xunfeiPptApi.checkProgress(sid);
300 301 if (progressResponse != null && progressResponse.data() != null) {
301   - XunfeiPptApi.ProgressResponseData progressData = progressResponse.data();
  302 + XunFeiPptApi.ProgressResponseData progressData = progressResponse.data();
302 303 System.out.println("PPT 构建状态: " + progressData.pptStatus());
303 304 if (progressData.totalPages() != null && progressData.donePages() != null) {
304 305 System.out.println("完成进度: " + progressData.donePages() + "/" + progressData.totalPages()
... ...