From 6cda03ea4ae2b331337bac208eb14389d3ce3b41 Mon Sep 17 00:00:00 2001 From: Yeaury <3144550951@qq.com> Date: Wed, 25 Dec 2024 17:18:24 +0800 Subject: [PATCH 1/3] add youdao translate function --- .../pom.xml | 61 +++++++++ .../youdaotranslate/AuthUtil.java | 59 +++++++++ .../YoudaoTranslateAutoConfiguration.java | 42 ++++++ .../YoudaoTranslateProperties.java | 46 +++++++ .../YoudaoTranslateService.java | 123 ++++++++++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + pom.xml | 1 + 7 files changed, 333 insertions(+) create mode 100644 community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml create mode 100644 community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/AuthUtil.java create mode 100644 community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateAutoConfiguration.java create mode 100644 community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateProperties.java create mode 100644 community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateService.java create mode 100644 community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml new file mode 100644 index 00000000..b51d1922 --- /dev/null +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml @@ -0,0 +1,61 @@ + + + + + + 4.0.0 + + + com.alibaba.cloud.ai + spring-ai-alibaba + ${revision} + ../../../pom.xml + + + spring-ai-alibaba-starter-function-calling-youdaotranslate + spring-ai-alibaba-starter-function-calling-youdao + youdao translate tool for Spring AI Alibaba + + + + org.springframework.ai + spring-ai-spring-boot-autoconfigure + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.springframework.boot + spring-boot-starter-webflux + + + + com.google.code.gson + gson + + + + + + spring-ai-alibaba-function-calling-translate + + diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/AuthUtil.java b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/AuthUtil.java new file mode 100644 index 00000000..b91f7f32 --- /dev/null +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/AuthUtil.java @@ -0,0 +1,59 @@ +/* + * Copyright 2024-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.cloud.ai.functioncalling.youdaotranslate; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +/** + * @author Yeaury + */ +public class AuthUtil { + + public static String calculateSign(String appKey, String appSecret, String q, String salt, String curtime) + throws NoSuchAlgorithmException { + String strSrc = appKey + getInput(q) + salt + curtime + appSecret; + return sha256(strSrc); + } + + private static String sha256(String strSrc) throws NoSuchAlgorithmException { + byte[] bt = strSrc.getBytes(); + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(bt); + byte[] bts = md.digest(); + StringBuilder des = new StringBuilder(); + for (byte b : bts) { + String tmp = (Integer.toHexString(b & 0xFF)); + if (tmp.length() == 1) { + des.append("0"); + } + des.append(tmp); + } + return des.toString(); + } + + private static String getInput(String q) { + if (q.length() > 20) { + String firstPart = q.substring(0, 10); + String lastPart = q.substring(q.length() - 10); + return firstPart + q.length() + lastPart; + } + else { + return q; + } + } + +} diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateAutoConfiguration.java b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateAutoConfiguration.java new file mode 100644 index 00000000..3e6c57e2 --- /dev/null +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateAutoConfiguration.java @@ -0,0 +1,42 @@ +/* + * Copyright 2024-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.cloud.ai.functioncalling.youdaotranslate; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Description; + +/** + * @author Yeaury + */ +@Configuration +@ConditionalOnClass(YoudaoTranslateService.class) +@EnableConfigurationProperties(YoudaoTranslateProperties.class) +@ConditionalOnProperty(prefix = "spring.ai.alibaba.functioncalling.youdao", name = "enabled", havingValue = "true") +public class YoudaoTranslateAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + @Description("use youdao translation to achieve translation") + public YoudaoTranslateService youdaoTranslateFunction(YoudaoTranslateProperties properties) { + return new YoudaoTranslateService(properties); + } + +} diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateProperties.java b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateProperties.java new file mode 100644 index 00000000..264faa7a --- /dev/null +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateProperties.java @@ -0,0 +1,46 @@ +/* + * Copyright 2024-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.cloud.ai.functioncalling.youdaotranslate; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * @author Yeaury + */ +@ConfigurationProperties(prefix = "spring.ai.alibaba.functioncalling.youdao") +public class YoudaoTranslateProperties { + + private String appKey; + + private String appSecret; + + public String getAppKey() { + return appKey; + } + + public void setAppKey(String appKey) { + this.appKey = appKey; + } + + public String getAppSecret() { + return appSecret; + } + + public void setAppSecret(String appSecret) { + this.appSecret = appSecret; + } + +} diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateService.java b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateService.java new file mode 100644 index 00000000..e09eb168 --- /dev/null +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateService.java @@ -0,0 +1,123 @@ +/* + * Copyright 2024-2025 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alibaba.cloud.ai.functioncalling.youdaotranslate; + +import com.fasterxml.jackson.annotation.JsonClassDescription; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.StringUtils; +import org.springframework.web.reactive.function.client.WebClient; +import org.springframework.web.util.UriComponentsBuilder; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Function; + +import static com.alibaba.cloud.ai.functioncalling.youdaotranslate.AuthUtil.calculateSign; + +/** + * @author Yeaury + */ +public class YoudaoTranslateService + implements Function { + + private static final Logger logger = LoggerFactory.getLogger(YoudaoTranslateService.class); + + private static final String YOUDAO_TRANSLATE_HOST_URL = "https://openapi.youdao.com/api"; + + private final String appKey; + + private final String appSecret; + + private final WebClient webClient; + + public YoudaoTranslateService(YoudaoTranslateProperties properties) { + this.appKey = properties.getAppKey(); + this.appSecret = properties.getAppSecret(); + this.webClient = WebClient.builder() + .defaultHeader(HttpHeaders.USER_AGENT, HttpHeaders.USER_AGENT) + .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE) + .defaultHeader(HttpHeaders.ACCEPT_ENCODING, "gzip, deflate") + .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .defaultHeader(HttpHeaders.ACCEPT_LANGUAGE, "zh-CN,zh;q=0.9,ja;q=0.8") + .codecs(configurer -> configurer.defaultCodecs().maxInMemorySize(5 * 1024 * 1024)) + .build(); + } + + @Override + public Response apply(Request request) { + if (request == null || !StringUtils.hasText(request.text) || !StringUtils.hasText(request.targetLanguage)) { + return null; + } + String curtime = String.valueOf(System.currentTimeMillis() / 1000); + String salt = UUID.randomUUID().toString(); + try { + String url = UriComponentsBuilder.fromHttpUrl(YOUDAO_TRANSLATE_HOST_URL) + .queryParam("q", request.text) + .queryParam("from", request.sourceLanguage) + .queryParam("to", request.targetLanguage) + .queryParam("appKey", appKey) + .queryParam("salt", salt) + .queryParam("sign", calculateSign(appKey, appSecret, request.text, salt, curtime)) + .queryParam("signType", "v3") + .queryParam("curtime", curtime) + .build() + .toUriString(); + + Mono response = webClient.get().uri(url).retrieve().bodyToMono(String.class); + String responseData = response.block(); + System.out.println(responseData); + assert responseData != null; + logger.info("Translation request: {}, response: {}", request.text, responseData); + Gson gson = new Gson(); + Map responseMap = gson.fromJson(responseData, new TypeToken>() { + }.getType()); + if (responseMap.containsKey("translation")) { + return new Response((List) responseMap.get("translation")); + } + } + catch (Exception e) { + logger.error("Failed to invoke Youdao translate API due to: {}", e.getMessage()); + return null; + } + return null; + } + + @JsonClassDescription("Request to translate text to a target language") + public record Request( + @JsonProperty(required = true, + value = "text") @JsonPropertyDescription("Content that needs to be translated") String text, + + @JsonProperty(required = true, + value = "sourceLanguage") @JsonPropertyDescription("Source language") String sourceLanguage, + + @JsonProperty(required = true, + value = "targetLanguage") @JsonPropertyDescription("Target language to translate into") String targetLanguage) { + } + + @JsonClassDescription("Response to translate text to a target language") + public record Response(List translatedTexts) { + } + +} diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..bb52e1c0 --- /dev/null +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.alibaba.cloud.ai.functioncalling.youdaotranslate.YoudaoTranslateAutoConfiguration diff --git a/pom.xml b/pom.xml index 69c58908..0435fdea 100644 --- a/pom.xml +++ b/pom.xml @@ -51,6 +51,7 @@ community/function-calling/spring-ai-alibaba-starter-function-calling-sinanews community/function-calling/spring-ai-alibaba-starter-function-calling-toutiaonews community/function-calling/spring-ai-alibaba-starter-function-calling-yuque + community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate community/document-readers/github-reader community/document-readers/poi-document-reader From 7dbfd8b17a3b92ca505ceb368206900e7bfe1f31 Mon Sep 17 00:00:00 2001 From: Zhang Yu <143883582+Yeaury@users.noreply.github.com> Date: Wed, 25 Dec 2024 18:18:30 +0800 Subject: [PATCH 2/3] rename plugin --- .../pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml index b51d1922..5c0e2958 100644 --- a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml @@ -28,7 +28,7 @@ spring-ai-alibaba-starter-function-calling-youdaotranslate - spring-ai-alibaba-starter-function-calling-youdao + spring-ai-alibaba-starter-function-calling-youdaotranslate youdao translate tool for Spring AI Alibaba @@ -56,6 +56,6 @@ - spring-ai-alibaba-function-calling-translate + spring-ai-alibaba-function-calling-youdaotranslate From bcb87e0457e8fc1515dd7eb243110d98f5242e63 Mon Sep 17 00:00:00 2001 From: Yeaury <3144550951@qq.com> Date: Fri, 27 Dec 2024 19:09:57 +0800 Subject: [PATCH 3/3] code format --- .../pom.xml | 1 + .../youdaotranslate/YoudaoTranslateAutoConfiguration.java | 2 +- .../youdaotranslate/YoudaoTranslateProperties.java | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml index 5c0e2958..6598210a 100644 --- a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/pom.xml @@ -32,6 +32,7 @@ youdao translate tool for Spring AI Alibaba + org.springframework.ai spring-ai-spring-boot-autoconfigure diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateAutoConfiguration.java b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateAutoConfiguration.java index 3e6c57e2..e6c04248 100644 --- a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateAutoConfiguration.java +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateAutoConfiguration.java @@ -29,7 +29,7 @@ @Configuration @ConditionalOnClass(YoudaoTranslateService.class) @EnableConfigurationProperties(YoudaoTranslateProperties.class) -@ConditionalOnProperty(prefix = "spring.ai.alibaba.functioncalling.youdao", name = "enabled", havingValue = "true") +@ConditionalOnProperty(prefix = "spring.ai.alibaba.functioncalling.youdaotranslate", name = "enabled", havingValue = "true") public class YoudaoTranslateAutoConfiguration { @Bean diff --git a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateProperties.java b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateProperties.java index 264faa7a..974c45db 100644 --- a/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateProperties.java +++ b/community/function-calling/spring-ai-alibaba-starter-function-calling-youdaotranslate/src/main/java/com/alibaba/cloud/ai/functioncalling/youdaotranslate/YoudaoTranslateProperties.java @@ -20,7 +20,7 @@ /** * @author Yeaury */ -@ConfigurationProperties(prefix = "spring.ai.alibaba.functioncalling.youdao") +@ConfigurationProperties(prefix = "spring.ai.alibaba.functioncalling.youdaotranslate") public class YoudaoTranslateProperties { private String appKey;