feat: add v3

This commit is contained in:
xxnuo
2025-11-02 22:11:48 +08:00
parent a7e564133d
commit 3e57e8ea3a
35 changed files with 40 additions and 3 deletions

3
deprecated/cpp/README.md Normal file
View File

@@ -0,0 +1,3 @@
# C++ version (deprecated)
Origianl version ( ~ v2.1.1 ) is deprecated, continue to develop in [golang version](../../v3/README.md)

View File

@@ -0,0 +1,35 @@
v3.0.4
- 修复模型自动更新逻辑
- 性能大幅提升,无论原文长短,单个请求平均响应时间 50ms
- 更新模型,提升翻译质量
- 性能大幅提升的代价是内存占用大幅上涨(英译中占用 2G 内存左右),请注意服务器配置。视用户需求是否推出更轻量级的模式。
v3.0.1 - v3.0.3
- 完全重写服务架构,提高稳定性和性能
- 添加 Swagger UI 接口文档
- 支持 HTTPS 安全连接
- 添加模型自动下载机制,使用更流畅
- 支持更多语言对的翻译
- 更新模型
v2.0.0
- 适配 ARM 架构
v1.1.1
- 添加流畅翻译插件支持
- 添加 OpenAI 接口支持
v1.1.0
- 修复部分标点符号会翻译成Unicode字符的问题
- 添加划词翻译插件支持
- 添加谷歌翻译兼容接口
- 修复内存溢出问题
v1.0.4
- 添加波兰语(pt)、波斯语(pl) 模型

22
deprecated/js/CONFIG.md Normal file
View File

@@ -0,0 +1,22 @@
# Advanced Settings
In the same directory as the `compose.yml` file, create a `config.ini` file and write the following content to modify as needed:
```ini
; API token, default empty
CORE_API_TOKEN=your_token
; Internal port, default 8989
CORE_PORT=8989
; Log level, default WARNING
CORE_LOG_LEVEL=WARNING
; Number of worker threads, default automatically set
CORE_NUM_WORKERS=
; Request timeout, default 30000ms
CORE_REQUEST_TIMEOUT=
; Maximum number of parallel translations, default automatically set
CORE_MAX_PARALLEL_TRANSLATIONS=
```
> You can also set the configuration using the same name in the environment variable.
>
> The entries in the `config.ini` file will override the environment variable settings.

29
deprecated/js/Dockerfile Normal file
View File

@@ -0,0 +1,29 @@
FROM node:lts-alpine AS builder
WORKDIR /app
COPY package.json package.json
COPY packages/ ./packages/
RUN npm install
FROM alpine:latest
RUN apk update && \
apk add --no-cache nodejs curl
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY js ./js
COPY package.json ./package.json
COPY start.sh ./start.sh
RUN chmod +x ./start.sh
EXPOSE 8989
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=8989
CMD ["./start.sh"]

View File

@@ -0,0 +1,44 @@
FROM node:lts-alpine AS builder
WORKDIR /app
COPY package.json package.json
COPY packages/ ./packages/
RUN npm install
COPY js/utils/preload.js ./js/utils/preload.js
COPY js/utils/translator.js ./js/utils/translator.js
ARG PRELOAD_SRC_LANG=""
ARG PRELOAD_TARGET_LANG=""
RUN if [ -n "$PRELOAD_SRC_LANG" ] ; then \
node js/utils/preload.js $PRELOAD_SRC_LANG en; \
fi
RUN if [ -n "$PRELOAD_TARGET_LANG" ]; then \
node js/utils/preload.js en $PRELOAD_TARGET_LANG; \
fi
FROM alpine:latest
RUN apk update && \
apk add --no-cache nodejs curl
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /root/.cache/mtran /root/.cache/mtran
COPY js ./js
COPY package.json ./package.json
COPY start.sh ./start.sh
RUN chmod +x ./start.sh
EXPOSE 8989
ENV NODE_ENV=production
ENV HOST=0.0.0.0
ENV PORT=8989
CMD ["./start.sh"]

46
deprecated/js/Makefile Normal file
View File

@@ -0,0 +1,46 @@
.PHONY: env prepare build test
env:
if pnpm -v > /dev/null 2>&1; then \
echo "pnpm is already installed"; \
else \
echo "pnpm is not installed, please install pnpm first!"; \
exit 1; \
fi
git pull
pnpm i -g nodemon
$(MAKE) update
update:
mkdir -p packages
LATEST_VERSION=$$(curl -s https://api.github.com/repos/xxnuo/MTranCore/releases/latest | grep -o '"tag_name": "v[^"]*"' | cut -d'"' -f4); \
echo "Downloading latest version: $$LATEST_VERSION"; \
curl -L "https://github.com/xxnuo/MTranCore/releases/download/$$LATEST_VERSION/mtran-core-$${LATEST_VERSION#v}.tgz" -o packages/mtran-core.tgz
build:
docker build -t xxnuo/mtranserver:test \
-f Dockerfile .
build-zh:
docker build -t xxnuo/mtranserver:test-zh \
--build-arg PRELOAD_SRC_LANG=zh-Hans \
--build-arg PRELOAD_TARGET_LANG=zh-Hans \
-f Dockerfile.model .
test: build
docker run -it --rm --name mtranserver-test -p 8989:8989 xxnuo/mtranserver:test
test-zh: build-zh
docker run -it --rm --name mtranserver-test-zh -p 8989:8989 xxnuo/mtranserver:test-zh
dev:
pnpm i
LOG_LEVEL=debug node --expose-gc js/mts.js
watch:
pnpm i
LOG_LEVEL=debug nodemon --watch js --ext js --exec "node --expose-gc js/mts.js"
trace:
pnpm i
LOG_LEVEL=debug node --expose-gc --inspect-brk js/mts.js

3
deprecated/js/README.md Normal file
View File

@@ -0,0 +1,3 @@
# Node.js version (deprecated)
Node.js version is deprecated, continue to develop in [golang version](../../v3/README.md)

34
deprecated/js/build.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/sh
if [ $# -eq 0 ]; then
echo "错误: 请提供版本号"
echo "用法: $0 <版本号>"
exit 1
fi
VERSION=$1
echo "开始构建版本: $VERSION"
# 构建标准版镜像(不预加载模型)
echo "构建标准版镜像 mtranserver:$VERSION..."
docker build -t xxnuo/mtranserver:$VERSION \
-t xxnuo/mtranserver:latest \
-f Dockerfile .
# 构建中文预加载版镜像
echo "构建中文预加载版镜像 mtranserver:${VERSION}-zh..."
docker build -t xxnuo/mtranserver:${VERSION}-zh \
-t xxnuo/mtranserver:latest-zh \
--build-arg PRELOAD_SRC_LANG=zh-Hans \
--build-arg PRELOAD_TARGET_LANG=en \
-f Dockerfile.model .
# 构建日语预加载版镜像
echo "构建日语预加载版镜像 mtranserver:${VERSION}-ja..."
docker build -t xxnuo/mtranserver:${VERSION}-ja \
-t xxnuo/mtranserver:latest-ja \
--build-arg PRELOAD_SRC_LANG=ja \
--build-arg PRELOAD_TARGET_LANG=en \
-f Dockerfile.model .
echo "构建完成!"

165
deprecated/js/js/mts.js Executable file
View File

@@ -0,0 +1,165 @@
#!/usr/bin/env node
const fastify = require("fastify");
const cors = require("@fastify/cors");
const swagger = require("@fastify/swagger");
const swaggerUi = require("@fastify/swagger-ui");
const { getConfig, validateToken } = require("./utils/config");
const { authenticate, errorHandler } = require("./utils/middleware");
const { shutdown } = require("./utils/translator");
const registerTranslateRoutes = require("./routes/translate");
const registerPluginRoutes = require("./routes/plugins");
const registerBaseRoutes = require("./routes/base");
// 获取配置
const config = getConfig();
// 创建Fastify实例
const server = fastify({
logger: {
level: config.logLevel,
transport: {
target: "pino-pretty",
options: {
translateTime: "HH:MM:ss Z",
ignore: "pid,hostname",
},
},
},
trustProxy: true, // 信任代理,允许获取正确的客户端 IP 和协议
});
// 注册CORS中间件
server.register(cors, {
origin: true,
methods: ["GET", "POST", "OPTIONS"],
allowedHeaders: ["Content-Type", "Authorization", "Key"],
});
// 注册Swagger生成器
server.register(swagger, {
openapi: {
info: {
title: "MTranServer API",
description: "MTranServer API documentation",
version: config.version || "3.0.0",
},
components: {
securitySchemes: {
Authorization: {
type: "apiKey",
name: "Authorization",
in: "header",
},
},
},
},
});
// 注册Swagger UI
server.register(swaggerUi, {
routePrefix: "/docs",
uiConfig: {
tryItOutEnabled: false,
persistAuthorization: true,
displayRequestDuration: true,
},
transformSpecification: (swaggerObject, request, reply) => {
// 动态调整 URL 协议,确保与请求协议一致
const protocol = request.protocol || "http";
swaggerObject.servers = [
{
url: `${protocol}://${config.host}:${config.port}`,
description: `MTranServer API (${protocol.toUpperCase()})`,
},
];
return swaggerObject;
},
uiHooks: {
onRequest: function (request, reply, next) {
next();
},
preHandler: function (request, reply, next) {
next();
},
},
staticCSP: false, // 禁用静态CSP以避免混合内容问题
transformStaticCSP: (header) => header,
});
// 设置错误处理器
server.setErrorHandler(errorHandler);
// 路由选项
const routeOptions = {
authenticate: authenticate,
validateToken: validateToken,
};
// 注册路由
server.register(registerBaseRoutes, routeOptions);
server.register(registerTranslateRoutes, routeOptions);
server.register(registerPluginRoutes, routeOptions);
// 启动服务器
async function start() {
try {
// 配置 HTTPS 选项
const listenOptions = {
port: config.port,
host: config.host,
};
// 如果配置了 HTTPS则添加 HTTPS 选项
if (config.https && config.httpsKey && config.httpsCert) {
const fs = require("fs");
listenOptions.https = {
key: fs.readFileSync(config.httpsKey),
cert: fs.readFileSync(config.httpsCert),
};
console.log(`HTTPS Service URL: https://${config.host}:${config.port}`);
console.log(`Swagger UI: https://${config.host}:${config.port}/docs`);
} else {
// 输出服务信息
console.log(`HTTP Service URL: http://${config.host}:${config.port}`);
console.log(`Swagger UI: http://${config.host}:${config.port}/docs`);
}
// 监听端口
await server.listen(listenOptions);
} catch (err) {
server.log.error(err);
process.exit(1);
}
}
// 处理进程退出
process.on("SIGINT", async () => {
console.log("Shutting down server...");
try {
await shutdown();
await server.close();
console.log("Server shutdown complete");
process.exit(0);
} catch (err) {
console.error("Error during shutdown:", err);
process.exit(1);
}
});
process.on("SIGTERM", async () => {
console.log("Shutting down server...");
try {
await shutdown();
await server.close();
console.log("Server shutdown complete");
process.exit(0);
} catch (err) {
console.error("Error during shutdown:", err);
process.exit(1);
}
});
// 启动服务器
start();

View File

@@ -0,0 +1,94 @@
const { getVersion } = require("../utils/config");
/**
* 注册核心路由
* @param {Object} fastify Fastify实例
* @param {Object} options 选项
*/
function registerBaseRoutes(fastify, options) {
// 版本信息
fastify.get(
"/version",
{
schema: {
description: "Get the version of the server",
response: {
200: {
type: "object",
properties: {
version: { type: "string" },
},
},
},
},
},
async (request, reply) => {
return { version: getVersion() };
}
);
// 健康检查
fastify.get(
"/health",
{
schema: {
description: "Get the health of the server",
response: {
200: {
type: "object",
properties: {
status: { type: "string" },
},
},
},
},
},
async (request, reply) => {
return { status: "ok" };
}
);
// 心跳检查
fastify.get(
"/__heartbeat__",
{
schema: {
description: "Get the heartbeat of the server",
response: {
200: {
type: "object",
properties: {
status: { type: "string" },
},
},
},
},
},
async (request, reply) => {
return { status: "ok" };
}
);
// 负载均衡心跳检查
fastify.get(
"/__lbheartbeat__",
{
schema: {
description: "Get the heartbeat of the server",
response: {
200: {
type: "object",
properties: {
status: { type: "string" },
},
},
},
},
},
async (request, reply) => {
return { status: "ok" };
}
);
}
module.exports = registerBaseRoutes;

View File

@@ -0,0 +1,21 @@
const immePlugin = require("./plugins/imme");
const kissPlugin = require("./plugins/kiss");
const googlePlugin = require("./plugins/google");
const deeplPlugin = require("./plugins/deepl");
const deeplxPlugin = require("./plugins/deeplx");
/**
* 注册翻译插件兼容路由
* @param {Object} fastify Fastify实例
* @param {Object} options 选项
*/
function registerPluginRoutes(fastify, options) {
// 加载各个插件
immePlugin(fastify, options);
kissPlugin(fastify, options);
googlePlugin(fastify, options);
deeplPlugin(fastify, options);
deeplxPlugin(fastify, options);
}
module.exports = registerPluginRoutes;

View File

@@ -0,0 +1,305 @@
const { translate, batchTranslate } = require("../../utils/translator");
const { validateToken } = require("../../utils/config");
/**
* DeepLX 翻译兼容API路由处理
* @param {Object} fastify Fastify实例
* @param {Object} options 选项
*/
function deeplPlugin(fastify, options) {
fastify.post(
"/deepl/v2/translate",
{
schema: {
description: "DeepLX v2 API",
tags: ["plugins"],
headers: {
type: "object",
properties: {
authorization: {
type: "string",
description: "token",
},
},
},
body: {
type: "object",
required: ["text", "target_lang"],
properties: {
text: {
oneOf: [
{ type: "string" },
{ type: "array", items: { type: "string" } },
],
description: "需要翻译的文本,可以是字符串或字符串数组",
},
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
response: {
200: {
type: "object",
properties: {
translations: {
type: "array",
items: {
type: "object",
properties: {
detected_source_language: {
type: "string",
description: "检测到的源语言",
},
text: { type: "string", description: "翻译结果" },
},
},
},
},
},
},
},
},
async (request, reply) => {
try {
// 验证Authorization头部
const authHeader = request.headers.authorization;
if (!validateToken(authHeader)) {
return reply.code(401).send({
error: "Unauthorized",
message: "Invalid or missing token",
});
}
const { text, source_lang, target_lang } = request.body;
const from = source_lang || "auto";
const to = target_lang;
// 处理单个文本或文本数组
if (Array.isArray(text)) {
const translatedTexts = await batchTranslate(text, from, to);
return {
translations: translatedTexts.map((translatedText) => ({
detected_source_language:
from === "auto" ? "AUTO" : from.toUpperCase(),
text: translatedText,
})),
};
} else {
const translatedText = await translate(text, from, to);
return {
translations: [
{
detected_source_language:
from === "auto" ? "AUTO" : from.toUpperCase(),
text: translatedText,
},
],
};
}
} catch (error) {
reply.code(500).send({
message: error.message,
});
}
}
);
fastify.post(
"/deepl/translate",
{
schema: {
description: "DeepLX API",
tags: ["plugins"],
headers: {
type: "object",
properties: {
authorization: {
type: "string",
description: "Bearer token",
},
},
},
querystring: {
type: "object",
properties: {
token: { type: "string", description: "访问令牌" },
},
},
body: {
type: "object",
required: ["text", "source_lang", "target_lang"],
properties: {
text: { type: "string", description: "需要翻译的文本" },
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
response: {
200: {
type: "object",
properties: {
alternatives: {
type: "array",
items: { type: "string" },
description: "备选翻译结果",
},
code: { type: "integer", description: "状态码" },
data: { type: "string", description: "翻译结果" },
id: { type: "integer", description: "请求ID" },
method: { type: "string", description: "翻译方法" },
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
},
},
},
async (request, reply) => {
try {
// 验证Authorization头部或URL参数中的token
const authHeader = request.headers.authorization;
const urlToken = request.query.token;
// 从Bearer token中提取token值
let tokenFromHeader = null;
if (authHeader && authHeader.startsWith("Bearer ")) {
tokenFromHeader = authHeader.substring(7);
}
// 检查token是否有效
if (!(validateToken(tokenFromHeader) || validateToken(urlToken))) {
return reply.code(401).send({
error: "Unauthorized",
message: "Invalid or missing token",
});
}
const { text, source_lang, target_lang } = request.body;
// 执行翻译
const translatedText = await translate(text, source_lang, target_lang);
// 构建符合DeepLX格式的响应
return {
alternatives: [],
code: 200,
data: translatedText,
id: 1, // Math.floor(Math.random() * 10000000000), // 生成随机ID
method: "Free",
source_lang: source_lang.toUpperCase(),
target_lang: target_lang.toUpperCase(),
};
} catch (error) {
reply.code(500).send({
code: 500,
message: error.message,
});
}
}
);
fastify.post(
"/deepl/v1/translate",
{
schema: {
description: "DeepLX v1 API",
tags: ["plugins"],
headers: {
type: "object",
properties: {
authorization: {
type: "string",
description: "Bearer token",
},
"content-type": {
type: "string",
description: "内容类型",
},
},
},
querystring: {
type: "object",
properties: {
token: { type: "string", description: "访问令牌" },
},
},
body: {
type: "object",
required: ["text", "source_lang", "target_lang"],
properties: {
text: { type: "string", description: "需要翻译的文本" },
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
response: {
200: {
type: "object",
properties: {
alternatives: {
type: "array",
items: { type: "string" },
description: "备选翻译结果",
},
code: { type: "integer", description: "状态码" },
data: { type: "string", description: "翻译结果" },
id: { type: "integer", description: "请求ID" },
method: { type: "string", description: "翻译方法" },
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
},
},
},
async (request, reply) => {
try {
// 验证Authorization头部或URL参数中的token
const authHeader = request.headers.authorization;
const urlToken = request.query.token;
// 从Bearer token中提取token值
let tokenFromHeader = null;
if (authHeader && authHeader.startsWith("Bearer ")) {
tokenFromHeader = authHeader.substring(7);
}
// 检查token是否有效
if (!(validateToken(tokenFromHeader) || validateToken(urlToken))) {
return reply.code(401).send({
error: "Unauthorized",
message: "Invalid or missing token",
});
}
const { text, source_lang, target_lang } = request.body;
// 执行翻译
const translatedText = await translate(text, source_lang, target_lang);
// 生成随机ID
// const id = Math.floor(Math.random() * 10000000000);
// 构建响应
return {
alternatives: [], // 实际应用中可能需要提供备选翻译
code: 200,
data: translatedText,
id: 2, // id,
method: "Pro",
source_lang: source_lang.toUpperCase(),
target_lang: target_lang.toUpperCase(),
};
} catch (error) {
reply.code(500).send({
code: 500,
message: error.message,
});
}
}
);
}
module.exports = deeplPlugin;

View File

@@ -0,0 +1,305 @@
const { translate, batchTranslate } = require("../../utils/translator");
const { validateToken } = require("../../utils/config");
/**
* DeepLX 翻译兼容API路由处理
* @param {Object} fastify Fastify实例
* @param {Object} options 选项
*/
function deeplPlugin(fastify, options) {
fastify.post(
"/deeplx/v2/translate",
{
schema: {
description: "DeepLX v2 API",
tags: ["plugins"],
headers: {
type: "object",
properties: {
authorization: {
type: "string",
description: "token",
},
},
},
body: {
type: "object",
required: ["text", "target_lang"],
properties: {
text: {
oneOf: [
{ type: "string" },
{ type: "array", items: { type: "string" } },
],
description: "需要翻译的文本,可以是字符串或字符串数组",
},
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
response: {
200: {
type: "object",
properties: {
translations: {
type: "array",
items: {
type: "object",
properties: {
detected_source_language: {
type: "string",
description: "检测到的源语言",
},
text: { type: "string", description: "翻译结果" },
},
},
},
},
},
},
},
},
async (request, reply) => {
try {
// 验证Authorization头部
const authHeader = request.headers.authorization;
if (!validateToken(authHeader)) {
return reply.code(401).send({
error: "Unauthorized",
message: "Invalid or missing token",
});
}
const { text, source_lang, target_lang } = request.body;
const from = source_lang || "auto";
const to = target_lang;
// 处理单个文本或文本数组
if (Array.isArray(text)) {
const translatedTexts = await batchTranslate(text, from, to);
return {
translations: translatedTexts.map((translatedText) => ({
detected_source_language:
from === "auto" ? "AUTO" : from.toUpperCase(),
text: translatedText,
})),
};
} else {
const translatedText = await translate(text, from, to);
return {
translations: [
{
detected_source_language:
from === "auto" ? "AUTO" : from.toUpperCase(),
text: translatedText,
},
],
};
}
} catch (error) {
reply.code(500).send({
message: error.message,
});
}
}
);
fastify.post(
"/deeplx/translate",
{
schema: {
description: "DeepLX API",
tags: ["plugins"],
headers: {
type: "object",
properties: {
authorization: {
type: "string",
description: "Bearer token",
},
},
},
querystring: {
type: "object",
properties: {
token: { type: "string", description: "访问令牌" },
},
},
body: {
type: "object",
required: ["text", "source_lang", "target_lang"],
properties: {
text: { type: "string", description: "需要翻译的文本" },
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
response: {
200: {
type: "object",
properties: {
alternatives: {
type: "array",
items: { type: "string" },
description: "备选翻译结果",
},
code: { type: "integer", description: "状态码" },
data: { type: "string", description: "翻译结果" },
id: { type: "integer", description: "请求ID" },
method: { type: "string", description: "翻译方法" },
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
},
},
},
async (request, reply) => {
try {
// 验证Authorization头部或URL参数中的token
const authHeader = request.headers.authorization;
const urlToken = request.query.token;
// 从Bearer token中提取token值
let tokenFromHeader = null;
if (authHeader && authHeader.startsWith("Bearer ")) {
tokenFromHeader = authHeader.substring(7);
}
// 检查token是否有效
if (!(validateToken(tokenFromHeader) || validateToken(urlToken))) {
return reply.code(401).send({
error: "Unauthorized",
message: "Invalid or missing token",
});
}
const { text, source_lang, target_lang } = request.body;
// 执行翻译
const translatedText = await translate(text, source_lang, target_lang);
// 构建符合DeepLX格式的响应
return {
alternatives: [],
code: 200,
data: translatedText,
id: 1, // Math.floor(Math.random() * 10000000000), // 生成随机ID
method: "Free",
source_lang: source_lang.toUpperCase(),
target_lang: target_lang.toUpperCase(),
};
} catch (error) {
reply.code(500).send({
code: 500,
message: error.message,
});
}
}
);
fastify.post(
"/deeplx/v1/translate",
{
schema: {
description: "DeepLX v1 API",
tags: ["plugins"],
headers: {
type: "object",
properties: {
authorization: {
type: "string",
description: "Bearer token",
},
"content-type": {
type: "string",
description: "内容类型",
},
},
},
querystring: {
type: "object",
properties: {
token: { type: "string", description: "访问令牌" },
},
},
body: {
type: "object",
required: ["text", "source_lang", "target_lang"],
properties: {
text: { type: "string", description: "需要翻译的文本" },
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
response: {
200: {
type: "object",
properties: {
alternatives: {
type: "array",
items: { type: "string" },
description: "备选翻译结果",
},
code: { type: "integer", description: "状态码" },
data: { type: "string", description: "翻译结果" },
id: { type: "integer", description: "请求ID" },
method: { type: "string", description: "翻译方法" },
source_lang: { type: "string", description: "源语言代码" },
target_lang: { type: "string", description: "目标语言代码" },
},
},
},
},
},
async (request, reply) => {
try {
// 验证Authorization头部或URL参数中的token
const authHeader = request.headers.authorization;
const urlToken = request.query.token;
// 从Bearer token中提取token值
let tokenFromHeader = null;
if (authHeader && authHeader.startsWith("Bearer ")) {
tokenFromHeader = authHeader.substring(7);
}
// 检查token是否有效
if (!(validateToken(tokenFromHeader) || validateToken(urlToken))) {
return reply.code(401).send({
error: "Unauthorized",
message: "Invalid or missing token",
});
}
const { text, source_lang, target_lang } = request.body;
// 执行翻译
const translatedText = await translate(text, source_lang, target_lang);
// 生成随机ID
// const id = Math.floor(Math.random() * 10000000000);
// 构建响应
return {
alternatives: [], // 实际应用中可能需要提供备选翻译
code: 200,
data: translatedText,
id: 2, // id,
method: "Pro",
source_lang: source_lang.toUpperCase(),
target_lang: target_lang.toUpperCase(),
};
} catch (error) {
reply.code(500).send({
code: 500,
message: error.message,
});
}
}
);
}
module.exports = deeplPlugin;

View File

@@ -0,0 +1,76 @@
const { translate } = require("../../utils/translator");
/**
* Google翻译兼容API路由处理
* @param {Object} fastify Fastify实例
* @param {Object} options 选项
*/
function googlePlugin(fastify, options) {
fastify.post(
"/google/language/translate/v2",
{
preHandler: options.authenticate,
schema: {
description: "Google翻译兼容API",
tags: ["plugins"],
body: {
type: "object",
required: ["q", "source", "target"],
properties: {
q: { type: "string", description: "需要翻译的文本" },
source: { type: "string", description: "源语言代码" },
target: { type: "string", description: "目标语言代码" },
format: { type: "string", default: "text", description: "文本格式默认为text" },
},
},
response: {
200: {
type: "object",
properties: {
data: {
type: "object",
properties: {
translations: {
type: "array",
items: {
type: "object",
properties: {
translatedText: { type: "string", description: "翻译结果" }
}
}
}
}
}
}
},
500: {
type: "object",
properties: {
error: { type: "string" },
message: { type: "string" }
}
}
}
},
},
async (request, reply) => {
const { q, source, target } = request.body;
try {
const translatedText = await translate(q, source, target);
return {
data: {
translations: [{ translatedText }],
},
};
} catch (error) {
reply.code(500).send({
error: "TranslationError",
message: error.message,
});
}
}
);
}
module.exports = googlePlugin;

View File

@@ -0,0 +1,131 @@
const { batchTranslate } = require("../../utils/translator");
const { validateToken } = require("../../utils/config");
/**
* 沉浸式翻译插件API路由处理
* @param {Object} fastify Fastify实例
* @param {Object} options 选项
*/
function immePlugin(fastify, options) {
fastify.post(
"/imme",
{
schema: {
description: "沉浸式翻译插件API",
tags: ["plugins"],
querystring: {
type: "object",
// 移除必需的token要求
properties: {
token: { type: "string", description: "token" },
},
},
body: {
type: "object",
properties: {
source_lang: {
type: "string",
description: "源语言代码默认为auto",
},
target_lang: {
type: "string",
description: "目标语言代码默认为zh-Hans",
},
text_list: {
type: "array",
description: "需要翻译的文本数组",
items: { type: "string" },
},
},
required: ["text_list"],
},
response: {
200: {
type: "object",
properties: {
translations: {
type: "array",
items: {
type: "object",
properties: {
detected_source_lang: {
type: "string",
description: "检测到的源语言代码",
},
text: { type: "string", description: "已翻译的文本" },
},
},
},
},
},
400: {
type: "object",
properties: {
error: { type: "string" },
message: { type: "string" },
},
},
401: {
type: "object",
properties: {
error: { type: "string" },
message: { type: "string" },
},
},
500: {
type: "object",
properties: {
error: { type: "string" },
message: { type: "string" },
},
},
},
},
},
async (request, reply) => {
// 验证token直接使用validateToken函数
const token = request.query.token;
if (!validateToken(token)) {
return reply.code(401).send({
error: "Unauthorized",
message: "Invalid or missing token",
});
}
try {
const { source_lang, target_lang, text_list } = request.body;
// 检查text_list是否为有效数组
if (!Array.isArray(text_list) || text_list.length === 0) {
return reply.code(400).send({
error: "BadRequest",
message: "text_list must be a non-empty array",
});
}
// 批量翻译
const translatedTexts = await batchTranslate(
text_list,
source_lang || "auto",
target_lang || "zh-Hans"
);
// 构建符合要求的响应格式
const translations = translatedTexts.map((text, index) => {
return {
detected_source_lang: source_lang || "auto", // 实际应该从翻译服务获取检测到的语言
text: text,
};
});
return { translations };
} catch (error) {
return reply
.code(500)
.send({ error: "TranslationError", message: error.message });
}
}
);
}
module.exports = immePlugin;

View File

@@ -0,0 +1,122 @@
const { translate, batchTranslate } = require("../../utils/translator");
const { validateToken } = require("../../utils/config");
/**
* 简约翻译插件API路由处理
* @param {Object} fastify Fastify实例
* @param {Object} options 选项
*/
function kissPlugin(fastify, options) {
fastify.post(
"/kiss",
{
schema: {
description: "简约翻译插件API",
tags: ["plugins"],
headers: {
type: "object",
properties: {
authorization: { type: "string", description: "Bearer token认证" },
},
},
body: {
type: "object",
properties: {
text: { type: "string", description: "待翻译文字" },
from: { type: "string", description: "源语言代码默认为auto" },
to: { type: "string", description: "目标语言代码默认为zh-CN" },
texts: {
type: "array",
description: "需要批量翻译的文本数组",
items: { type: "string" },
},
},
anyOf: [{ required: ["text"] }, { required: ["texts"] }],
},
response: {
200: {
type: "object",
properties: {
text: { type: "string", description: "翻译后的文字" },
from: { type: "string", description: "识别的源语言" },
to: { type: "string", description: "目标语言" },
},
},
400: {
type: "object",
properties: {
error: { type: "string" },
message: { type: "string" },
},
},
401: {
type: "object",
properties: {
error: { type: "string" },
message: { type: "string" },
},
},
500: {
type: "object",
properties: {
error: { type: "string" },
message: { type: "string" },
},
},
},
},
},
async (request, reply) => {
// 从Authorization头部提取token
const authHeader = request.headers.authorization || "";
const token = authHeader.startsWith("Bearer ")
? authHeader.substring(7)
: null;
if (!validateToken(token)) {
return reply.code(401).send({
error: "Unauthorized",
message: "Invalid or missing API token",
});
}
try {
const { from, to, text, texts } = request.body;
const targetLang = to || "zh-CN";
const sourceLang = from || "auto";
// 处理批量翻译
if (Array.isArray(texts) && texts.length > 0) {
const results = await batchTranslate(texts, sourceLang, targetLang);
return {
text: results.join("\n"),
from: sourceLang,
to: targetLang,
};
}
// 处理单个文本翻译
if (text) {
const result = await translate(text, sourceLang, targetLang);
return {
text: result,
from: sourceLang,
to: targetLang,
};
}
return reply.code(400).send({
error: "BadRequest",
message: "Missing text or texts parameter",
});
} catch (error) {
return reply.code(500).send({
error: "TranslationError",
message: error.message,
});
}
}
);
}
module.exports = kissPlugin;

View File

@@ -0,0 +1,178 @@
const {
translate,
batchTranslate,
supportedLanguages,
} = require("../utils/translator");
/**
* 注册翻译路由
* @param {Object} fastify Fastify实例
* @param {Object} options 选项
*/
function registerTranslateRoutes(fastify, options) {
// 获取已加载的模型列表
fastify.get(
"/languages",
{
preHandler: options.authenticate,
schema: {
description:
"Get the supported languages. Use this endpoint to get the language codes for translation.",
security: [{ Authorization: [] }],
headers: {
type: "object",
properties: {
Authorization: {
type: "string",
description:
"API token for authentication (format: 'your_token')",
},
},
},
response: {
200: {
type: "object",
properties: {
languages: {
type: "array",
items: { type: "string" },
description: "The supported languages",
},
},
},
},
},
},
async (request, reply) => {
return { languages: supportedLanguages };
}
);
// 普通翻译API
fastify.post(
"/translate",
{
preHandler: options.authenticate,
schema: {
description:
"Translate a text. Use this endpoint to translate a single text; from: The source language. Recommend using language code from /languages endpoint. Use 'auto' for automatic detection (adds ~0.04s delay). For Chinese translation, 'zh-Hans' is more efficient than 'zh-CN'; to: The target language. Using language code from /languages endpoint. For Chinese translation, 'zh-Hans' is more efficient than 'zh-CN'; text: The text to translate",
security: [{ Authorization: [] }],
headers: {
type: "object",
properties: {
Authorization: {
type: "string",
description:
"API token for authentication (format: 'your_token')",
},
},
},
body: {
type: "object",
required: ["from", "to", "text"],
properties: {
from: {
type: "string",
description:
"The source language. Recommend using language code from /languages endpoint. Use 'auto' for automatic detection (adds ~0.04s delay). For Chinese translation, 'zh-Hans' is more efficient than 'zh-CN'",
default: "auto",
enum: ["auto", ...supportedLanguages],
},
to: {
type: "string",
description:
"The target language. Using language code from /languages endpoint. For Chinese translation, 'zh-Hans' is more efficient than 'zh-CN'",
default: "zh-Hans",
enum: supportedLanguages,
},
text: {
type: "string",
description: "The text to translate",
default: "Do as you would be done by",
},
},
},
},
},
async (request, reply) => {
const { from, to, text } = request.body;
try {
const result = await translate(text, from, to);
return { result };
} catch (error) {
reply.code(500).send({
error: "TranslationError",
message: error.message,
});
}
}
);
// 批量翻译API
fastify.post(
"/translate/batch",
{
preHandler: options.authenticate,
schema: {
description:
"Translate a batch of texts. Use this endpoint to translate a batch of texts. from: The source language. Recommend using language code from /languages endpoint. Use 'auto' for automatic detection (adds ~0.04s delay). For Chinese translation, 'zh-Hans' is more efficient than 'zh-CN'; to: The target language. Using language code from /languages endpoint. For Chinese translation, 'zh-Hans' is more efficient than 'zh-CN'; texts: The texts to translate",
security: [{ Authorization: [] }],
headers: {
type: "object",
properties: {
Authorization: {
type: "string",
description:
"API token for authentication (format: 'your_token')",
},
},
},
body: {
type: "object",
required: ["from", "to", "texts"],
properties: {
from: {
type: "string",
description:
"The source language. Recommend using language code from /languages endpoint. Use 'auto' for automatic detection (adds ~0.04s delay). For Chinese translation, 'zh-Hans' is more efficient than 'zh-CN'",
default: "auto",
enum: ["auto", ...supportedLanguages],
},
to: {
type: "string",
description:
"The target language. Using language code from /languages endpoint. For Chinese translation, 'zh-Hans' is more efficient than 'zh-CN'",
default: "zh-Hans",
enum: supportedLanguages,
},
texts: {
type: "array",
items: {
type: "string",
default: "Do as you would be done by",
},
default: ["Do as you would be done by", "Do unto others"],
description: "The texts to translate",
},
},
},
},
},
async (request, reply) => {
const { from, to, texts } = request.body;
try {
const results = await batchTranslate(texts, from, to);
return { results };
} catch (error) {
reply.code(500).send({
error: "BatchTranslationError",
message: error.message,
});
}
}
);
}
module.exports = registerTranslateRoutes;

View File

@@ -0,0 +1,50 @@
/**
* 配置管理模块
*/
// 默认配置
const defaultConfig = {
port: process.env.PORT || 8989,
host: process.env.HOST || "0.0.0.0",
apiToken: process.env.API_TOKEN || process.env.CORE_API_TOKEN || "", // 兼容旧版本
logLevel: process.env.LOG_LEVEL || "warn",
https: process.env.HTTPS === "true" || false,
httpsKey: process.env.HTTPS_KEY || "",
httpsCert: process.env.HTTPS_CERT || "",
};
/**
* 获取配置
* @returns {Object} 配置对象
*/
function getConfig() {
return { ...defaultConfig };
}
/**
* 验证API令牌
* @param {string} token 待验证的令牌
* @returns {boolean} 是否有效
*/
function validateToken(token) {
// 如果未设置API令牌则不需要验证
if (defaultConfig.apiToken === "") {
return true;
}
return token === defaultConfig.apiToken;
}
/**
* 获取服务器版本
* @returns {string} 版本号
*/
function getVersion() {
const packageJson = require("../../package.json");
return packageJson.version || "unknown";
}
module.exports = {
getConfig,
validateToken,
getVersion,
};

View File

@@ -0,0 +1,42 @@
const { validateToken } = require("./config");
/**
* 认证中间件
* @param {Object} request Fastify请求对象
* @param {Object} reply Fastify响应对象
* @param {Function} done 完成回调
*/
function authenticate(request, reply, done) {
const authHeader = request.headers.authorization;
const token = request.query.token;
// 检查Authorization头或URL中的token参数
if (validateToken(authHeader) || validateToken(token)) {
done();
} else {
reply
.code(401)
.send({ error: "Unauthorized", message: "Invalid or missing API token" });
}
}
/**
* 错误处理中间件
* @param {Error} error 错误对象
* @param {Object} request Fastify请求对象
* @param {Object} reply Fastify响应对象
*/
function errorHandler(error, request, reply) {
console.error(`Error processing request: ${error.message}`);
// 返回适当的错误响应
reply.code(error.statusCode || 500).send({
error: error.name || "InternalServerError",
message: error.message || "An unknown error occurred",
});
}
module.exports = {
authenticate,
errorHandler,
};

View File

@@ -0,0 +1,26 @@
const { preloadModel, supportedLanguages, shutdown } = require("./translator");
// 如果直接执行此脚本,则从命令行参数获取语言对并预加载
async function main() {
if (require.main === module) {
const args = process.argv.slice(2);
if (args.length !== 2) {
console.log("Usage: node preload.js <from> <to>");
console.log("Available languages:", supportedLanguages.join(", "));
process.exit(1);
}
const [from, to] = args;
try {
console.log(`Preloading model for ${from} to ${to}...`);
await preloadModel(from, to);
console.log("Preload completed successfully.");
await shutdown();
} catch (error) {
console.error("Error during preload:", error.message);
process.exit(1);
}
}
}
main();

View File

@@ -0,0 +1,76 @@
const Translator = require("@mtran/core");
const loadedLangs = new Set();
let supportedLanguages = Translator.GetSupportLanguages();
function checkSupportLanguage(from, to) {
return (
(supportedLanguages.includes(from) || from === "auto") &&
supportedLanguages.includes(to)
);
}
/**
* 预加载翻译模型
* @param {string} from 源语言
* @param {string} to 目标语言
* @returns {Promise<void>}
*/
async function preloadModel(from, to) {
if (!checkSupportLanguage(from, to)) {
throw new Error("Unsupported language pair");
}
const modelKey = `${from}_${to}`;
if (!loadedLangs.has(modelKey)) {
await Translator.Preload(from, to);
loadedLangs.add(modelKey);
console.log(`Successfully loaded model for language pair: ${modelKey}`);
}
}
/**
* 翻译文本
* @param {string} text 要翻译的文本
* @param {string} from 源语言
* @param {string} to 目标语言
* @returns {Promise<string>} 翻译结果
*/
async function translate(text, from, to) {
if (!checkSupportLanguage(from, to)) {
throw new Error("Unsupported language pair");
}
return Translator.Translate(text, from, to);
}
/**
* 批量翻译文本
* @param {string[]} texts 要翻译的文本数组
* @param {string} from 源语言
* @param {string} to 目标语言
* @returns {Promise<string[]>} 翻译结果数组
*/
async function batchTranslate(texts, from, to) {
if (!checkSupportLanguage(from, to)) {
throw new Error("Unsupported language pair");
}
// 并行处理翻译请求
const promises = texts.map((text) => Translator.Translate(text, from, to));
return Promise.all(promises);
}
/**
* 关闭翻译引擎
* @returns {Promise<void>}
*/
async function shutdown() {
await Translator.Shutdown();
console.log("Translation engine shutdown complete");
}
module.exports = {
supportedLanguages,
preloadModel,
translate,
batchTranslate,
shutdown,
};

View File

@@ -0,0 +1,13 @@
{
"restartable": "rs",
"ignore": [
".git",
"node_modules/**/node_modules",
"packages"
],
"verbose": true,
"watch": [
"js/"
],
"ext": "js,json"
}

View File

@@ -0,0 +1,31 @@
{
"name": "@mtran/server",
"homepage": "https://github.com/xxnuo",
"version": "3.0.4",
"type": "commonjs",
"main": "js/mts.js",
"bin": {
"mt": "js/mts.js"
},
"keywords": [
"translation",
"offline",
"bergamot",
"machine-translation",
"nlp",
"node"
],
"author": "xxnuo",
"license": "Apache-2.0",
"engines": {
"node": ">=18.0.0"
},
"dependencies": {
"@fastify/cors": "^11.0.1",
"@fastify/swagger": "^9.5.1",
"@fastify/swagger-ui": "^5.2.3",
"@mtran/core": "file:packages/mtran-core.tgz",
"fastify": "^5.4.0",
"pino-pretty": "^13.0.0"
}
}

Binary file not shown.

25
deprecated/js/start.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/sh
# 翻译服务器启动脚本
# 获取脚本所在目录的绝对路径
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
# 切换到脚本所在目录
cd "$SCRIPT_DIR" || exit 1
# 检查是否设置了环境变量
if [ -z "$PORT" ]; then
export PORT=8989
fi
if [ -z "$HOST" ]; then
export HOST=0.0.0.0
fi
# 启动服务
echo "Starting MTranServer..."
node js/mts.js
# 脚本结束
exit 0

36
deprecated/js/test.sh Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/sh
# 测试运行脚本
# 获取脚本所在目录的绝对路径
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
# 切换到脚本所在目录
cd "$SCRIPT_DIR" || exit 1
# 设置环境变量
export HOST=${HOST:-localhost}
export PORT=${PORT:-8989}
export CORE_API_TOKEN=${CORE_API_TOKEN:-}
# 显示测试环境
echo "测试环境:"
echo "HOST: $HOST"
echo "PORT: $PORT"
echo "TOKEN: ${CORE_API_TOKEN:-(未设置)}"
echo ""
# 运行测试
echo "=== 运行核心API测试 ==="
node tests/base.js
echo ""
echo "=== 运行翻译API测试 ==="
node tests/translate.js
echo ""
echo "=== 运行翻译插件兼容API测试 ==="
node tests/plugin.js
echo ""
echo "所有测试完成!"

184
deprecated/js/tests/base.js Executable file
View File

@@ -0,0 +1,184 @@
#!/usr/bin/env node
/**
* 测试核心API
* 包括版本、健康检查、心跳检查和模型列表API
*/
const http = require('http');
// 配置
const config = {
host: process.env.HOST || 'localhost',
port: process.env.PORT || 8989,
token: process.env.CORE_API_TOKEN || ''
};
// 测试版本API
function testVersion() {
console.log('测试版本API...');
const options = {
hostname: config.host,
port: config.port,
path: '/version',
method: 'GET'
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${data}`);
console.log('版本API测试完成\n');
// 测试下一个API
testHealth();
});
});
req.on('error', (error) => {
console.error(`版本API测试出错: ${error.message}`);
});
req.end();
}
// 测试健康检查API
function testHealth() {
console.log('测试健康检查API...');
const options = {
hostname: config.host,
port: config.port,
path: '/health',
method: 'GET'
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${data}`);
console.log('健康检查API测试完成\n');
// 测试下一个API
testHeartbeat();
});
});
req.on('error', (error) => {
console.error(`健康检查API测试出错: ${error.message}`);
});
req.end();
}
// 测试心跳检查API
function testHeartbeat() {
console.log('测试心跳检查API...');
const options = {
hostname: config.host,
port: config.port,
path: '/__heartbeat__',
method: 'GET'
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${data}`);
console.log('心跳检查API测试完成\n');
// 测试下一个API
testLBHeartbeat();
});
});
req.on('error', (error) => {
console.error(`心跳检查API测试出错: ${error.message}`);
});
req.end();
}
// 测试负载均衡心跳检查API
function testLBHeartbeat() {
console.log('测试负载均衡心跳检查API...');
const options = {
hostname: config.host,
port: config.port,
path: '/__lbheartbeat__',
method: 'GET'
};
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${data}`);
console.log('负载均衡心跳检查API测试完成\n');
// 测试下一个API
testModels();
});
});
req.on('error', (error) => {
console.error(`负载均衡心跳检查API测试出错: ${error.message}`);
});
req.end();
}
// 测试模型列表API
function testModels() {
console.log('测试模型列表API...');
const options = {
hostname: config.host,
port: config.port,
path: '/models',
method: 'GET',
headers: {}
};
// 如果有token添加到请求头
if (config.token) {
options.headers['Authorization'] = config.token;
}
const req = http.request(options, (res) => {
let data = '';
res.on('data', (chunk) => {
data += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${data}`);
console.log('模型列表API测试完成\n');
console.log('所有核心API测试完成');
});
});
req.on('error', (error) => {
console.error(`模型列表API测试出错: ${error.message}`);
});
req.end();
}
// 开始测试
console.log('开始测试核心API...\n');
testVersion();

241
deprecated/js/tests/plugins.js Executable file
View File

@@ -0,0 +1,241 @@
#!/usr/bin/env node
/**
* 测试翻译插件兼容API
* 包括沉浸式翻译、简约翻译和划词翻译API
*/
const http = require('http');
// 配置
const config = {
host: process.env.HOST || 'localhost',
port: process.env.PORT || 8989,
token: process.env.CORE_API_TOKEN || ''
};
// 测试沉浸式翻译API
function testImmeTranslate() {
console.log('测试沉浸式翻译API...');
const tokenParam = config.token ? `?token=${config.token}` : '';
const options = {
hostname: config.host,
port: config.port,
path: `/imme${tokenParam}`,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
const data = JSON.stringify({
source_lang: 'en',
target_lang: 'zh-Hans',
text: 'Hello, world!'
});
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${responseData}`);
console.log('沉浸式翻译API测试完成\n');
// 测试批量翻译
testImmeBatchTranslate();
});
});
req.on('error', (error) => {
console.error(`沉浸式翻译API测试出错: ${error.message}`);
});
req.write(data);
req.end();
}
// 测试沉浸式翻译批量API
function testImmeBatchTranslate() {
console.log('测试沉浸式翻译批量API...');
const tokenParam = config.token ? `?token=${config.token}` : '';
const options = {
hostname: config.host,
port: config.port,
path: `/imme${tokenParam}`,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
const data = JSON.stringify({
source_lang: 'en',
target_lang: 'zh-Hans',
texts: ['Hello, world!', 'How are you?']
});
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${responseData}`);
console.log('沉浸式翻译批量API测试完成\n');
// 测试下一个API
testKissTranslate();
});
});
req.on('error', (error) => {
console.error(`沉浸式翻译批量API测试出错: ${error.message}`);
});
req.write(data);
req.end();
}
// 测试简约翻译API
function testKissTranslate() {
console.log('测试简约翻译API...');
const options = {
hostname: config.host,
port: config.port,
path: '/kiss',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
// 如果有token添加到请求头
if (config.token) {
options.headers['Key'] = config.token;
}
const data = JSON.stringify({
from: 'en',
to: 'zh-Hans',
text: 'Hello, world!'
});
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${responseData}`);
console.log('简约翻译API测试完成\n');
// 测试批量翻译
testKissBatchTranslate();
});
});
req.on('error', (error) => {
console.error(`简约翻译API测试出错: ${error.message}`);
});
req.write(data);
req.end();
}
// 测试简约翻译批量API
function testKissBatchTranslate() {
console.log('测试简约翻译批量API...');
const options = {
hostname: config.host,
port: config.port,
path: '/kiss',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
// 如果有token添加到请求头
if (config.token) {
options.headers['Key'] = config.token;
}
const data = JSON.stringify({
from: 'en',
to: 'zh-Hans',
texts: ['Hello, world!', 'How are you?']
});
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${responseData}`);
console.log('简约翻译批量API测试完成\n');
// 测试下一个API
testHcfyTranslate();
});
});
req.on('error', (error) => {
console.error(`简约翻译批量API测试出错: ${error.message}`);
});
req.write(data);
req.end();
}
// 测试划词翻译API
function testHcfyTranslate() {
console.log('测试划词翻译API...');
const tokenParam = config.token ? `?token=${config.token}` : '';
const options = {
hostname: config.host,
port: config.port,
path: `/hcfy${tokenParam}`,
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
const data = JSON.stringify({
text: 'Hello, world!',
from: 'en',
to: 'zh-Hans'
});
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${responseData}`);
console.log('划词翻译API测试完成\n');
console.log('所有翻译插件兼容API测试完成');
});
});
req.on('error', (error) => {
console.error(`划词翻译API测试出错: ${error.message}`);
});
req.write(data);
req.end();
}
// 开始测试
console.log('开始测试翻译插件兼容API...\n');
testImmeTranslate();

160
deprecated/js/tests/translate.js Executable file
View File

@@ -0,0 +1,160 @@
#!/usr/bin/env node
/**
* 测试翻译API
* 包括普通翻译、批量翻译和Google翻译兼容API
*/
const http = require('http');
// 配置
const config = {
host: process.env.HOST || 'localhost',
port: process.env.PORT || 8989,
token: process.env.CORE_API_TOKEN || ''
};
// 测试普通翻译API
function testTranslate() {
console.log('测试普通翻译API...');
const options = {
hostname: config.host,
port: config.port,
path: '/translate',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
// 如果有token添加到请求头
if (config.token) {
options.headers['Authorization'] = config.token;
}
const data = JSON.stringify({
from: 'en',
to: 'zh-Hans',
text: 'Hello, world!'
});
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${responseData}`);
console.log('普通翻译API测试完成\n');
// 测试下一个API
testBatchTranslate();
});
});
req.on('error', (error) => {
console.error(`普通翻译API测试出错: ${error.message}`);
});
req.write(data);
req.end();
}
// 测试批量翻译API
function testBatchTranslate() {
console.log('测试批量翻译API...');
const options = {
hostname: config.host,
port: config.port,
path: '/translate/batch',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
// 如果有token添加到请求头
if (config.token) {
options.headers['Authorization'] = config.token;
}
const data = JSON.stringify({
from: 'en',
to: 'zh-Hans',
texts: ['Hello, world!', 'How are you?']
});
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${responseData}`);
console.log('批量翻译API测试完成\n');
// 测试下一个API
testGoogleTranslate();
});
});
req.on('error', (error) => {
console.error(`批量翻译API测试出错: ${error.message}`);
});
req.write(data);
req.end();
}
// 测试Google翻译兼容API
function testGoogleTranslate() {
console.log('测试Google翻译兼容API...');
const options = {
hostname: config.host,
port: config.port,
path: '/language/translate/v2',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
// 如果有token添加到请求头
if (config.token) {
options.headers['Authorization'] = config.token;
}
const data = JSON.stringify({
q: 'The Great Pyramid of Giza',
source: 'en',
target: 'zh-Hans',
format: 'text'
});
const req = http.request(options, (res) => {
let responseData = '';
res.on('data', (chunk) => {
responseData += chunk;
});
res.on('end', () => {
console.log(`状态码: ${res.statusCode}`);
console.log(`响应数据: ${responseData}`);
console.log('Google翻译兼容API测试完成\n');
console.log('所有翻译API测试完成');
});
});
req.on('error', (error) => {
console.error(`Google翻译兼容API测试出错: ${error.message}`);
});
req.write(data);
req.end();
}
// 开始测试
console.log('开始测试翻译API...\n');
testTranslate();

View File

@@ -0,0 +1,7 @@
# Rust version (community version)
Performance improvement is not significant, only works in x86_64 Linux and some APIs are not compatible with the original version, recommend to use [golang version](../../v3/README.md) instead.
Rust server source code is in [LinguaSpark/server](https://github.com/LinguaSpark/server)
Rust core source code is in [LinguaSpark/core](https://github.com/LinguaSpark/core)