xf 翻译

This commit is contained in:
ran.shang
2025-06-24 16:24:57 +08:00
parent 2649ec853f
commit 6def8d1023
8 changed files with 304 additions and 3 deletions

View File

@@ -0,0 +1,33 @@
package com.newyetai.ai.controller;
import com.newyetai.common.AlitaResult;
import com.newyetai.sdk.xf.model.ChatReq;
import com.newyetai.sdk.xf.model.TranslateReq;
import com.newyetai.sdk.xf.util.XfUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(tags = "ai")
@RestController
@RequestMapping("/ai")
public class AiController {
@PostMapping("chat")
@ApiOperation("ai对话")
public AlitaResult<String> chat(@Validated @RequestBody ChatReq req) {
return AlitaResult.success(XfUtils.chat(req));
}
@PostMapping("translate")
@ApiOperation("ai翻译")
public AlitaResult<String> chat(@Validated @RequestBody TranslateReq req) {
return AlitaResult.success(XfUtils.translate(req));
}
}

View File

@@ -34,5 +34,8 @@ public class XfProperties implements Serializable{
private String iatHostUrl; private String iatHostUrl;
/** 语音合成地址 **/ /** 语音合成地址 **/
private String ttsHostUrl; private String ttsHostUrl;
/** 机器翻译niutrans **/
private String otsHostUrl;
} }

View File

@@ -3,6 +3,7 @@ package com.newyetai.sdk.xf.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@@ -19,6 +20,7 @@ public class ChatReq implements Serializable{
@Default @Default
private String model = "4.0Ultra"; private String model = "4.0Ultra";
@Singular @Singular
@NotNull(message = "消息内容不能为空")
private List<MessageDTO> messages; private List<MessageDTO> messages;

View File

@@ -0,0 +1,67 @@
package com.newyetai.sdk.xf.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.newyetai.sdk.common.dto.ISdkRequest;
import com.newyetai.sdk.xf.model.TranslateReq.TranslateRes;
import javax.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.core.ParameterizedTypeReference;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class TranslateReq implements ISdkRequest<XfRes<TranslateRes>> {
private static ParameterizedTypeReference<XfRes<TranslateRes>> type = new ParameterizedTypeReference<XfRes<TranslateRes>>() {
};
/** 中文 */
private static final String CN = "cn";
/** 维语 */
private static final String UY = "uy";
@NotBlank(message = "待翻译文本不能为空")
private String text;
@Default
private String from = CN;
@Default
private String to = UY;
@Override
public ParameterizedTypeReference getResponseType() {
return type;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class TranslateRes {
private TranslateResDTO result;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class TranslateResDTO {
private String from;
private String to;
@JsonProperty("trans_result")
private TranslateResultDTO transResult;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class TranslateResultDTO {
private String src;
private String dst;
}
}

View File

@@ -0,0 +1,19 @@
package com.newyetai.sdk.xf.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class XfRes<T> {
private Integer code;
private String message;
private String sid;
private T data;
}

View File

@@ -1,5 +1,24 @@
package com.newyetai.sdk.xf.service; package com.newyetai.sdk.xf.service;
import com.google.gson.JsonObject;
import com.newyetai.common.constant.CommonConstants;
import com.newyetai.sdk.xf.model.TranslateReq;
import com.newyetai.sdk.xf.model.TranslateReq.TranslateRes;
import com.newyetai.sdk.xf.model.XfRes;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
@@ -67,6 +86,149 @@ public class XfSparkProvider {
public static String dealJson(String content) { public static String dealJson(String content) {
return content.replaceAll("(```json\n)|(\n```)|(\n)", ""); return content.replaceAll("(```json\n)|(\n```)|(\n)", "");
} }
public static AlitaResult<String> translate(TranslateReq translateReq){
return translate(translateReq, xfProperties);
}
public static AlitaResult<String> translate(TranslateReq translateReq, XfProperties xfProperties){
ResponseEntity<XfRes<TranslateRes>> response = null;
try {
try {
String body = buildHttpBody(translateReq, xfProperties);
HttpHeaders header = buildHttpHeader(body, xfProperties);
// 发送请求
HttpEntity requestEntity = new HttpEntity(body, header);
response =
HttpUtils.restTemplate.exchange(xfProperties.getOtsHostUrl(),
HttpMethod.POST, requestEntity, translateReq.getResponseType());
} catch (Exception e) {
log.error("xfSpark http error:{}", e.getMessage());
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage());
}
try {
XfRes<TranslateRes> res = response.getBody();
if (!res.getCode().equals(0)) {
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE,
res.getCode() + CommonConstants.COLON + res.getMessage());
}
return AlitaResult.success(res.getData().getResult().getTransResult().getDst());
} catch (Exception e) {
return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE, "xf返回结果获取content失败");
}
} finally {
log.info("xfSpark invoke:{}",
JsonUtils
.toJsonString(
DefaultSdkInvokeLogDTO.builder().requestData(translateReq).responseData(response)
.build()));
}
}
/**
* 组装http请求头
*/
public static HttpHeaders buildHttpHeader(String body, XfProperties xfProperties)
throws MalformedURLException, NoSuchAlgorithmException, InvalidKeyException {
HttpHeaders header = new HttpHeaders();
URL url = new URL(xfProperties.getOtsHostUrl());
//时间戳
SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("GMT"));
Date dateD = new Date();
String date = format.format(dateD);
//System.out.println("【OTS WebAPI date】\n" + date);
//对body进行sha256签名,生成digest头部,POST请求必须对body验证
String digestBase64 = "SHA-256=" + signBody(body);
//System.out.println("【OTS WebAPI digestBase64】\n" + digestBase64);
//hmacsha256加密原始字符串
StringBuilder builder = new StringBuilder("host: ").append(url.getHost()).append("\n").//
append("date: ").append(date).append("\n").//
append("POST ").append(url.getPath()).append(" HTTP/1.1").append("\n").//
append("digest: ").append(digestBase64);
//System.out.println("【OTS WebAPI builder】\n" + builder);
String sha = hmacsign(builder.toString(), xfProperties.getApiSecret());
//System.out.println("【OTS WebAPI sha】\n" + sha);
//组装authorization
String authorization = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"", xfProperties.getApiKey(), "hmac-sha256", "host date request-line digest", sha);
//System.out.println("【OTS WebAPI authorization】\n" + authorization);
header.add("Authorization", authorization);
header.add("Content-Type", "application/json");
header.add("Accept", "application/json,version=1.0");
header.add("Host", url.getHost());
header.add("Date", date);
header.add("Digest", digestBase64);
//System.out.println("【OTS WebAPI header】\n" + header);
return header;
}
/**
* 组装http请求体
*/
public static String buildHttpBody(TranslateReq translateReq, XfProperties xfProperties)
throws UnsupportedEncodingException {
JsonObject body = new JsonObject();
JsonObject business = new JsonObject();
JsonObject common = new JsonObject();
JsonObject data = new JsonObject();
//填充common
common.addProperty("app_id", xfProperties.getAppId());
//填充business
business.addProperty("from", translateReq.getFrom());
business.addProperty("to", translateReq.getTo());
//填充data
//System.out.println("【OTS WebAPI TEXT字个数:】\n" + TEXT.length());
byte[] textByte = translateReq.getText().getBytes("UTF-8");
String textBase64 = new String(Base64.getEncoder().encodeToString(textByte));
//System.out.println("【OTS WebAPI textBase64编码后长度:】\n" + textBase64.length());
data.addProperty("text", textBase64);
//填充body
body.add("common", common);
body.add("business", business);
body.add("data", data);
return body.toString();
}
/**
* 对body进行SHA-256加密
*/
private static String signBody(String body) {
MessageDigest messageDigest;
String encodestr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(body.getBytes("UTF-8"));
encodestr = Base64.getEncoder().encodeToString(messageDigest.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encodestr;
}
/**
* hmacsha256加密
*/
private static String hmacsign(String signature, String apiSecret)
throws NoSuchAlgorithmException, InvalidKeyException {
Charset charset = Charset.forName("UTF-8");
Mac mac = Mac.getInstance("hmacsha256");
SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(charset), "hmacsha256");
mac.init(spec);
byte[] hexDigits = mac.doFinal(signature.getBytes(charset));
return Base64.getEncoder().encodeToString(hexDigits);
}
} }

View File

@@ -1,5 +1,6 @@
package com.newyetai.sdk.xf.util; package com.newyetai.sdk.xf.util;
import com.newyetai.sdk.xf.model.TranslateReq;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -229,4 +230,16 @@ public class XfUtils {
return result.getData(); return result.getData();
} }
public static String chat(ChatReq req) {
AlitaResult<String> result = XfSparkProvider.httpChat(req);
Assert.isTrue(result.getSuccess(), result.getMsg());
return result.getData();
}
public static String translate(TranslateReq req) {
AlitaResult<String> result = XfSparkProvider.translate(req);
Assert.isTrue(result.getSuccess(), result.getMsg());
return result.getData();
}
} }

View File

@@ -156,13 +156,15 @@ ali.idcard.appcode=728e8c05167a482093418707ca22822b
#讯飞配置 #讯飞配置
xf.httpAPIPassword=EiORVeNtBjFOcUSKXanT:oIVlTRNhWcEDpksviZaG xf.httpAPIPassword=EiORVeNtBjFOcUSKXanT:oIVlTRNhWcEDpksviZaG
#在控制台-我的应用获取 #在控制台-我的应用获取
xf.appId=a2847f13 xf.appId=83b8ddca
xf.apiSecret=ZGYzYjY5N2E2ODJhYzJkZWNjMjBmMWU5 xf.apiSecret=ZWE2MjkzY2VmZDkwM2EwZGJhNGRhOWJm
xf.apiKey=a232b25616c1359d15c30711c1976de6 xf.apiKey=e092f93e28ebe6d27f756bb2d884dcff
#语音听写地址 #语音听写地址
xf.iatHostUrl=https://iat-api.xfyun.cn/v2/iat xf.iatHostUrl=https://iat-api.xfyun.cn/v2/iat
#语音合成地址 #语音合成地址
xf.ttsHostUrl=https://tts-api.xfyun.cn/v2/tts xf.ttsHostUrl=https://tts-api.xfyun.cn/v2/tts
#机器翻译niutrans
xf.otsHostUrl=https://ntrans.xfyun.cn/v2/ots
#腾讯地图 #腾讯地图
tencent.map.key=TS7BZ-GOVCB-CUZUL-JUUAV-WTYT3-Z2B4Z tencent.map.key=TS7BZ-GOVCB-CUZUL-JUUAV-WTYT3-Z2B4Z