mirror of
https://github.com/xxnuo/MTranServer.git
synced 2026-09-03 06:35:20 +08:00
feat: add v3
This commit is contained in:
3
deprecated/cpp/README.md
Normal file
3
deprecated/cpp/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# C++ version (deprecated)
|
||||
|
||||
Origianl version ( ~ v2.1.1 ) is deprecated, continue to develop in [golang version](../../v3/README.md)
|
||||
35
deprecated/js/CHANGELOG.md
Normal file
35
deprecated/js/CHANGELOG.md
Normal 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
22
deprecated/js/CONFIG.md
Normal 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
29
deprecated/js/Dockerfile
Normal 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"]
|
||||
44
deprecated/js/Dockerfile.model
Normal file
44
deprecated/js/Dockerfile.model
Normal 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
46
deprecated/js/Makefile
Normal 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
3
deprecated/js/README.md
Normal 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
34
deprecated/js/build.sh
Executable 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
165
deprecated/js/js/mts.js
Executable 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();
|
||||
94
deprecated/js/js/routes/base.js
Normal file
94
deprecated/js/js/routes/base.js
Normal 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;
|
||||
21
deprecated/js/js/routes/plugins.js
Normal file
21
deprecated/js/js/routes/plugins.js
Normal 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;
|
||||
305
deprecated/js/js/routes/plugins/deepl.js
Normal file
305
deprecated/js/js/routes/plugins/deepl.js
Normal 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;
|
||||
305
deprecated/js/js/routes/plugins/deeplx.js
Normal file
305
deprecated/js/js/routes/plugins/deeplx.js
Normal 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;
|
||||
76
deprecated/js/js/routes/plugins/google.js
Normal file
76
deprecated/js/js/routes/plugins/google.js
Normal 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;
|
||||
131
deprecated/js/js/routes/plugins/imme.js
Normal file
131
deprecated/js/js/routes/plugins/imme.js
Normal 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;
|
||||
122
deprecated/js/js/routes/plugins/kiss.js
Normal file
122
deprecated/js/js/routes/plugins/kiss.js
Normal 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;
|
||||
178
deprecated/js/js/routes/translate.js
Normal file
178
deprecated/js/js/routes/translate.js
Normal 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;
|
||||
50
deprecated/js/js/utils/config.js
Normal file
50
deprecated/js/js/utils/config.js
Normal 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,
|
||||
};
|
||||
42
deprecated/js/js/utils/middleware.js
Normal file
42
deprecated/js/js/utils/middleware.js
Normal 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,
|
||||
};
|
||||
26
deprecated/js/js/utils/preload.js
Normal file
26
deprecated/js/js/utils/preload.js
Normal 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();
|
||||
76
deprecated/js/js/utils/translator.js
Normal file
76
deprecated/js/js/utils/translator.js
Normal 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,
|
||||
};
|
||||
13
deprecated/js/nodemon.json
Normal file
13
deprecated/js/nodemon.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"restartable": "rs",
|
||||
"ignore": [
|
||||
".git",
|
||||
"node_modules/**/node_modules",
|
||||
"packages"
|
||||
],
|
||||
"verbose": true,
|
||||
"watch": [
|
||||
"js/"
|
||||
],
|
||||
"ext": "js,json"
|
||||
}
|
||||
31
deprecated/js/package.json
Normal file
31
deprecated/js/package.json
Normal 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"
|
||||
}
|
||||
}
|
||||
BIN
deprecated/js/packages/mtran-core.tgz
Normal file
BIN
deprecated/js/packages/mtran-core.tgz
Normal file
Binary file not shown.
25
deprecated/js/start.sh
Executable file
25
deprecated/js/start.sh
Executable 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
36
deprecated/js/test.sh
Executable 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
184
deprecated/js/tests/base.js
Executable 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
241
deprecated/js/tests/plugins.js
Executable 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
160
deprecated/js/tests/translate.js
Executable 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();
|
||||
7
deprecated/rust/README.md
Normal file
7
deprecated/rust/README.md
Normal 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)
|
||||
Reference in New Issue
Block a user