2023-07-20 13:45:41 +08:00
|
|
|
|
import queryString from "query-string";
|
2024-04-21 13:16:44 +08:00
|
|
|
|
import { fetchData } from "../libs/fetch";
|
2023-07-20 13:45:41 +08:00
|
|
|
|
import {
|
2023-10-20 17:44:48 +08:00
|
|
|
|
URL_CACHE_TRAN,
|
2023-08-20 23:30:08 +08:00
|
|
|
|
KV_SALT_SYNC,
|
2024-05-22 23:33:30 +08:00
|
|
|
|
URL_GOOGLE_TRAN,
|
2023-10-10 18:03:05 +08:00
|
|
|
|
OPT_LANGS_BAIDU,
|
2023-10-21 11:54:04 +08:00
|
|
|
|
OPT_LANGS_TENCENT,
|
|
|
|
|
|
OPT_LANGS_SPECIAL,
|
2024-05-22 23:33:30 +08:00
|
|
|
|
OPT_LANGS_MICROSOFT,
|
2023-07-20 13:45:41 +08:00
|
|
|
|
} from "../config";
|
2023-08-20 23:30:08 +08:00
|
|
|
|
import { sha256 } from "../libs/utils";
|
2024-05-22 23:33:30 +08:00
|
|
|
|
import { msAuth } from "../libs/auth";
|
2025-07-03 18:08:49 +08:00
|
|
|
|
import { kissLog } from "../libs/log";
|
2025-08-31 23:37:29 +08:00
|
|
|
|
import { genTransReq, parseTransRes } from "./trans";
|
|
|
|
|
|
import { getHttpCachePolyfill, putHttpCachePolyfill } from "../libs/cache";
|
2023-07-20 13:45:41 +08:00
|
|
|
|
|
2023-07-31 15:08:51 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 同步数据
|
|
|
|
|
|
* @param {*} url
|
|
|
|
|
|
* @param {*} key
|
|
|
|
|
|
* @param {*} data
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
2023-09-20 17:47:23 +08:00
|
|
|
|
export const apiSyncData = async (url, key, data) =>
|
2024-04-21 13:16:44 +08:00
|
|
|
|
fetchData(url, {
|
2023-08-21 23:46:42 +08:00
|
|
|
|
headers: {
|
|
|
|
|
|
"Content-type": "application/json",
|
|
|
|
|
|
Authorization: `Bearer ${await sha256(key, KV_SALT_SYNC)}`,
|
2023-07-31 15:08:51 +08:00
|
|
|
|
},
|
2023-08-21 23:46:42 +08:00
|
|
|
|
method: "POST",
|
|
|
|
|
|
body: JSON.stringify(data),
|
|
|
|
|
|
});
|
2023-07-31 15:08:51 +08:00
|
|
|
|
|
2023-08-30 18:05:37 +08:00
|
|
|
|
/**
|
2023-09-08 21:41:32 +08:00
|
|
|
|
* 下载数据
|
2023-08-30 18:05:37 +08:00
|
|
|
|
* @param {*} url
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
2024-04-21 13:16:44 +08:00
|
|
|
|
export const apiFetch = (url) => fetchData(url);
|
2023-08-30 18:05:37 +08:00
|
|
|
|
|
2024-05-22 23:33:30 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* Google语言识别
|
|
|
|
|
|
* @param {*} text
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const apiGoogleLangdetect = async (text) => {
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
client: "gtx",
|
|
|
|
|
|
dt: "t",
|
|
|
|
|
|
dj: 1,
|
|
|
|
|
|
ie: "UTF-8",
|
|
|
|
|
|
sl: "auto",
|
|
|
|
|
|
tl: "zh-CN",
|
|
|
|
|
|
q: text,
|
|
|
|
|
|
};
|
|
|
|
|
|
const input = `${URL_GOOGLE_TRAN}?${queryString.stringify(params)}`;
|
2025-08-31 23:37:29 +08:00
|
|
|
|
const init = {
|
2024-05-22 23:33:30 +08:00
|
|
|
|
headers: {
|
|
|
|
|
|
"Content-type": "application/json",
|
|
|
|
|
|
},
|
2025-08-31 23:37:29 +08:00
|
|
|
|
};
|
|
|
|
|
|
const res = await fetchData(input, init, { useCache: true });
|
|
|
|
|
|
|
|
|
|
|
|
if (res?.src) {
|
|
|
|
|
|
await putHttpCachePolyfill(input, init, res);
|
|
|
|
|
|
return res.src;
|
|
|
|
|
|
}
|
2024-05-22 23:33:30 +08:00
|
|
|
|
|
2025-08-31 23:37:29 +08:00
|
|
|
|
return "";
|
2024-05-22 23:33:30 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* Microsoft语言识别
|
|
|
|
|
|
* @param {*} text
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const apiMicrosoftLangdetect = async (text) => {
|
|
|
|
|
|
const [token] = await msAuth();
|
2025-08-31 23:37:29 +08:00
|
|
|
|
const input =
|
|
|
|
|
|
"https://api-edge.cognitive.microsofttranslator.com/detect?api-version=3.0";
|
|
|
|
|
|
const init = {
|
2024-05-22 23:33:30 +08:00
|
|
|
|
headers: {
|
|
|
|
|
|
"Content-type": "application/json",
|
|
|
|
|
|
Authorization: `Bearer ${token}`,
|
|
|
|
|
|
},
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
body: JSON.stringify([{ Text: text }]),
|
2025-08-31 23:37:29 +08:00
|
|
|
|
};
|
|
|
|
|
|
const res = await fetchData(input, init, {
|
2024-05-22 23:33:30 +08:00
|
|
|
|
useCache: true,
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-08-31 23:37:29 +08:00
|
|
|
|
if (res[0].language) {
|
|
|
|
|
|
await putHttpCachePolyfill(input, init, res);
|
|
|
|
|
|
return OPT_LANGS_MICROSOFT.get(res[0].language) ?? res[0].language;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return "";
|
2024-05-22 23:33:30 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2023-07-20 13:45:41 +08:00
|
|
|
|
/**
|
2023-10-21 11:54:04 +08:00
|
|
|
|
* 百度语言识别
|
2023-07-31 03:10:09 +08:00
|
|
|
|
* @param {*} text
|
|
|
|
|
|
* @returns
|
2023-07-20 13:45:41 +08:00
|
|
|
|
*/
|
2023-10-21 11:54:04 +08:00
|
|
|
|
export const apiBaiduLangdetect = async (text) => {
|
2025-08-31 23:37:29 +08:00
|
|
|
|
const input = "https://fanyi.baidu.com/langdetect";
|
|
|
|
|
|
const init = {
|
2023-08-22 16:27:09 +08:00
|
|
|
|
headers: {
|
|
|
|
|
|
"Content-type": "application/json",
|
2023-07-20 13:45:41 +08:00
|
|
|
|
},
|
2023-08-22 16:27:09 +08:00
|
|
|
|
method: "POST",
|
|
|
|
|
|
body: JSON.stringify({
|
2023-10-21 11:54:04 +08:00
|
|
|
|
query: text,
|
2023-08-22 16:27:09 +08:00
|
|
|
|
}),
|
2025-08-31 23:37:29 +08:00
|
|
|
|
};
|
|
|
|
|
|
const res = await fetchData(input, init, { useCache: true });
|
2023-09-06 14:57:02 +08:00
|
|
|
|
|
2023-10-21 11:54:04 +08:00
|
|
|
|
if (res.error === 0) {
|
2025-08-31 23:37:29 +08:00
|
|
|
|
await putHttpCachePolyfill(input, init, res);
|
2023-10-21 11:54:04 +08:00
|
|
|
|
return OPT_LANGS_BAIDU.get(res.lan) ?? res.lan;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return "";
|
2023-09-06 00:25:46 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2024-03-19 11:48:30 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 百度翻译建议
|
|
|
|
|
|
* @param {*} text
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const apiBaiduSuggest = async (text) => {
|
2025-08-31 23:37:29 +08:00
|
|
|
|
const input = "https://fanyi.baidu.com/sug";
|
|
|
|
|
|
const init = {
|
2024-03-19 11:48:30 +08:00
|
|
|
|
headers: {
|
|
|
|
|
|
"Content-type": "application/json",
|
|
|
|
|
|
},
|
|
|
|
|
|
method: "POST",
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
kw: text,
|
|
|
|
|
|
}),
|
2025-08-31 23:37:29 +08:00
|
|
|
|
};
|
|
|
|
|
|
const res = await fetchData(input, init, { useCache: true });
|
2024-03-19 11:48:30 +08:00
|
|
|
|
|
|
|
|
|
|
if (res.errno === 0) {
|
2025-08-31 23:37:29 +08:00
|
|
|
|
await putHttpCachePolyfill(input, init, res);
|
2024-03-19 11:48:30 +08:00
|
|
|
|
return res.data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return [];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2024-03-25 18:14:12 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 百度语音
|
|
|
|
|
|
* @param {*} text
|
|
|
|
|
|
* @param {*} lan
|
|
|
|
|
|
* @param {*} spd
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
|
|
|
|
|
export const apiBaiduTTS = (text, lan = "uk", spd = 3) => {
|
2025-08-31 23:37:29 +08:00
|
|
|
|
const input = `https://fanyi.baidu.com/gettts?${queryString.stringify({ lan, text, spd })}`;
|
|
|
|
|
|
return fetchData(input);
|
2024-03-25 18:14:12 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2023-09-06 00:25:46 +08:00
|
|
|
|
/**
|
2023-10-21 11:54:04 +08:00
|
|
|
|
* 腾讯语言识别
|
2023-09-06 00:25:46 +08:00
|
|
|
|
* @param {*} text
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
2023-10-21 11:54:04 +08:00
|
|
|
|
export const apiTencentLangdetect = async (text) => {
|
2025-08-31 23:37:29 +08:00
|
|
|
|
const input = "https://transmart.qq.com/api/imt";
|
2023-10-21 11:54:04 +08:00
|
|
|
|
const body = JSON.stringify({
|
|
|
|
|
|
header: {
|
|
|
|
|
|
fn: "text_analysis",
|
2023-09-06 00:25:46 +08:00
|
|
|
|
},
|
2023-10-21 11:54:04 +08:00
|
|
|
|
text,
|
2023-08-22 16:27:09 +08:00
|
|
|
|
});
|
2025-08-31 23:37:29 +08:00
|
|
|
|
const init = {
|
2023-10-10 18:03:05 +08:00
|
|
|
|
headers: {
|
|
|
|
|
|
"Content-type": "application/json",
|
|
|
|
|
|
},
|
|
|
|
|
|
method: "POST",
|
2023-10-21 11:54:04 +08:00
|
|
|
|
body,
|
2025-08-31 23:37:29 +08:00
|
|
|
|
};
|
|
|
|
|
|
const res = await fetchData(input, init, { useCache: true });
|
|
|
|
|
|
|
|
|
|
|
|
if (res.language) {
|
|
|
|
|
|
await putHttpCachePolyfill(input, init, res);
|
|
|
|
|
|
return OPT_LANGS_TENCENT.get(res.language) ?? res.language;
|
|
|
|
|
|
}
|
2023-10-10 18:03:05 +08:00
|
|
|
|
|
2025-08-31 23:37:29 +08:00
|
|
|
|
return "";
|
2023-10-10 18:03:05 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2023-07-20 13:45:41 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 统一翻译接口
|
|
|
|
|
|
* @param {*} param0
|
|
|
|
|
|
* @returns
|
|
|
|
|
|
*/
|
2023-10-20 17:44:48 +08:00
|
|
|
|
export const apiTranslate = async ({
|
2023-08-30 18:05:37 +08:00
|
|
|
|
translator,
|
2023-09-06 14:57:02 +08:00
|
|
|
|
text,
|
2023-08-30 18:05:37 +08:00
|
|
|
|
fromLang,
|
|
|
|
|
|
toLang,
|
2023-10-20 17:44:48 +08:00
|
|
|
|
apiSetting = {},
|
|
|
|
|
|
useCache = true,
|
|
|
|
|
|
usePool = true,
|
2023-08-30 18:05:37 +08:00
|
|
|
|
}) => {
|
2025-08-31 23:37:29 +08:00
|
|
|
|
let cacheInput; // 缓存URL
|
|
|
|
|
|
let resCache; // 缓存对象
|
|
|
|
|
|
let res; // 翻译接口返回的JSON数据
|
2023-10-13 10:48:01 +08:00
|
|
|
|
|
2023-11-07 17:52:33 +08:00
|
|
|
|
if (!text) {
|
2025-08-31 23:37:29 +08:00
|
|
|
|
return ["", false];
|
2023-11-07 17:52:33 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-10-21 11:54:04 +08:00
|
|
|
|
const from =
|
|
|
|
|
|
OPT_LANGS_SPECIAL[translator].get(fromLang) ??
|
|
|
|
|
|
OPT_LANGS_SPECIAL[translator].get("auto");
|
|
|
|
|
|
const to = OPT_LANGS_SPECIAL[translator].get(toLang);
|
2023-11-07 17:52:33 +08:00
|
|
|
|
if (!to) {
|
2025-07-03 18:08:49 +08:00
|
|
|
|
kissLog(`target lang: ${toLang} not support`, "translate");
|
2025-08-31 23:37:29 +08:00
|
|
|
|
return ["", false];
|
2023-10-21 11:54:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-31 23:37:29 +08:00
|
|
|
|
// 查询缓存数据
|
|
|
|
|
|
// TODO: 优化缓存失效因素
|
|
|
|
|
|
if (useCache) {
|
|
|
|
|
|
const [v1, v2] = process.env.REACT_APP_VERSION.split(".");
|
|
|
|
|
|
const cacheOpts = {
|
|
|
|
|
|
translator,
|
|
|
|
|
|
text,
|
|
|
|
|
|
fromLang,
|
|
|
|
|
|
toLang,
|
|
|
|
|
|
userPrompt: apiSetting.userPrompt, // prompt改变,缓存失效
|
|
|
|
|
|
model: apiSetting.model, // model改变,缓存失效
|
|
|
|
|
|
version: [v1, v2].join("."),
|
|
|
|
|
|
};
|
|
|
|
|
|
cacheInput = `${URL_CACHE_TRAN}?${queryString.stringify(cacheOpts)}`;
|
|
|
|
|
|
resCache = await getHttpCachePolyfill(cacheInput);
|
|
|
|
|
|
}
|
2023-10-13 10:48:01 +08:00
|
|
|
|
|
2025-08-31 23:37:29 +08:00
|
|
|
|
// 请求接口数据
|
|
|
|
|
|
if (!resCache) {
|
|
|
|
|
|
const [input, init] = await genTransReq(translator, {
|
|
|
|
|
|
text,
|
|
|
|
|
|
from,
|
|
|
|
|
|
to,
|
|
|
|
|
|
...apiSetting,
|
|
|
|
|
|
});
|
|
|
|
|
|
res = await fetchData(input, init, {
|
|
|
|
|
|
useCache: false,
|
|
|
|
|
|
usePool,
|
|
|
|
|
|
fetchInterval: apiSetting.fetchInterval,
|
|
|
|
|
|
fetchLimit: apiSetting.fetchLimit,
|
|
|
|
|
|
httpTimeout: apiSetting.httpTimeout,
|
|
|
|
|
|
});
|
|
|
|
|
|
} else {
|
|
|
|
|
|
res = resCache;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!res) {
|
|
|
|
|
|
return ["", false];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析返回数据
|
|
|
|
|
|
const [trText, isSame] = parseTransRes(translator, res, apiSetting, {
|
2023-10-21 11:54:04 +08:00
|
|
|
|
text,
|
|
|
|
|
|
from,
|
|
|
|
|
|
to,
|
2025-08-31 23:37:29 +08:00
|
|
|
|
});
|
2023-07-20 13:45:41 +08:00
|
|
|
|
|
2025-08-31 23:37:29 +08:00
|
|
|
|
// 插入缓存
|
|
|
|
|
|
if (useCache && !resCache && trText) {
|
|
|
|
|
|
await putHttpCachePolyfill(cacheInput, null, res);
|
2023-07-20 13:45:41 +08:00
|
|
|
|
}
|
2023-10-20 17:44:48 +08:00
|
|
|
|
|
2023-10-21 11:54:04 +08:00
|
|
|
|
return [trText, isSame, res];
|
2023-07-20 13:45:41 +08:00
|
|
|
|
};
|