diff --git a/README.md b/README.md index 4fe3eac..e8a4848 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,41 @@ # DeepLX Serverless -DeepLX 免费翻译API**函数部署版**,与[原项目DeepLX](https://github.com/OwO-Network/DeepLX)的区别在于**利用了云函数的请求IP不固定的特性,极大程度上避免了`429`请求太频繁报错** +DeepLX 免费翻译API**函数部署版**,与原项目[DeepLX](https://github.com/OwO-Network/DeepLX)的区别在于**利用了无服务器函数(也叫边缘函数)的请求IP不固定的特性,极大程度上避免了`429`请求太频繁报错** -## Usage | 用法 +**如果本项目对你有用的话,不妨点个`Star`❤️** +**Click `Star` if you like!! thanks❤️** +## Major Changes | 重大改变 +> *vvvvery big changes🤣 + +如果您在这之前不使用本项目,此部分可以跳过。 +1. 新增了docker部署支持 +2. 请求参数变化: `alternative_number` -> `alt_count` + +## Let's Go | 开始使用 ### Prerequisites | 你需要准备什么 - 一双灵活的小手 - 一个聪明的脑袋瓜 -- 安装nodejs +- 支持 `Nodejs ≥16.13` 或 `Serverless Function` 的服务器 ### Deploy | 部署 -使用任意支持云函数部署的服务器,比如可以使用vercel进行部署,又或者其他能够使用nodejs的服务器。(几乎大多数服务器提供商都提供函数计算服务器) +使用任意支持无服务器函数部署的服务器,比如可以使用 `Vercel` 或者 `Netlify` 进行部署,又或者其他能够使用nodejs的服务器。(大多数服务器提供商都提供函数计算服务器) + +如果你拥有[Vercel](https://vercel.com)账号的话那就很简单了,因为你只需要点击下方按钮即可一键部署到Vercel: + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/guobao2333/DeepLX-Serverless) -如果你拥有[vercel](https://vercel.com)账号的话那就很简单了,因为你只需要点击下方按钮即可一键部署到Vercel: + -项目当前没有任何需要填写的变量值,但在后续可能会添加。 +因维护者我有多个仓库需要维护,短时间内将无法对多平台部署方案进行兼容,您可以选择**自托管**方案。 +✨项目当前没有任何需要填写的变量值,你只需要直接部署就可以用了,但在后续可能会添加。 +如果部署完成了,就可以开始使用啦!🎉 #### Docker 直接运行容器: @@ -33,71 +49,55 @@ docker build -t deeplx-api . docker run -d -p 9000:9000 deeplx-api ``` -#### 自托管 +#### Self hosting | 自托管 -尽管本项目是专为 serverless 适配的方案,但是也能使用自己的服务器进行部署: +✅尽管本项目是专为 serverless 适配的方案,但是也能使用自己的服务器进行部署: ```bash -git clone https://github.com/guobao/DeepLX-Serverless +git clone https://github.com/guobao2333/DeepLX-Serverless cd DeepLX-Serverless npm i npm run start ``` -直接复制到命令行运行: +📋直接复制到命令行运行: ```bash -git clone https://github.com/guobao/DeepLX-Serverless && cd DeepLX-Serverless && npm i && npm run start +git clone https://github.com/guobao2333/DeepLX-Serverless && cd DeepLX-Serverless && npm i && npm run start ``` -你可以运行`npm run test`用来测试翻译接口。 +🚧你可以运行`npm run test`用来测试翻译接口。 +⚠️注意!测试命令仅返回翻译内容,获取所有结果需要使用`POST`! ### How To Use | 如何使用 -使用post通过 `域名` + `/translate` + `json请求体` 这样的形式获取json响应。 +使用post通过 `域名地址` + `/translate` + `json请求体` 这样的形式获取json响应。 -请求示例: -```bash -curl --location --request POST 'https://YOUR-DOMAIN/translate' \ ---header 'Content-Type: application/json' \ ---data-raw '{ - "text": "Hello, World!", - "source_lang": "en", - "target_lang": "zh", - "alternative_number": 3 -}' -``` +详细API文档,请查看本项目的wiki: +[English](https://github.com/guobao2333/DeepLX-Serverless/wiki/English-document) | [简体中文](https://github.com/guobao2333/DeepLX-Serverless/wiki/%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87) -直接复制到命令行运行本地测试: +📋你可以直接复制到命令行运行**本地测试:** ```bash -curl --location 'http://localhost:9000/translate' --header 'Content-Type: application/json' --data '{"text": "你好,世界!", "source_lang": "zh", "target_lang": "en", "alternative_number": 3}' -``` - -**请修改`YOUR-DOMAIN`为你部署服务的域名!!** - ------------------ - -响应示例: -```json -{ - "code": 200, - "message": "success", - "data": "Hello, world.", - "source_lang": "en", - "target_lang": "zh", - "alternatives": ["Hello, World.", "Hello, world!", "Hi, world."] -} +curl --location --request POST 'http://localhost:9000/translate' --header 'Content-Type: application/json' --data '{"text": "你好,世界!", "source_lang": "zh", "target_lang": "en"}' ``` -部署完成后,建议搭配浏览器插件「沉浸式翻译」一同使用。 +✨部署完成后,建议搭配浏览器插件「沉浸式翻译」一同使用。 ## 沉浸式翻译设置 1. 在浏览器上安装最新的 [沉浸式翻译](https://github.com/immersive-translate/immersive-translate/releases)。 2. 点击左下角的 "开发者设置"。启用测试版实验功能。 3. 翻译服务选中 `DeepLX(beta)` -3. 设置 URL 为刚才获取的访问路径(需带translate)。 +4. 设置 URL 为刚才获取的访问路径(需带translate)。 ![沉浸式翻译](https://github.com/LegendLeo/deeplx-serverless/assets/25115173/d3affe2b-9e99-4d5c-bc8c-cd67e70d0368) +## Contribute | 贡献 + +> [!IMPORTANT] +> **在您做出贡献之前,请先切换到`dev`分支!!** +> 因为解决分支冲突真的很麻烦! + +本人因时间(和各种各样的)原因,故无法及时对您的贡献进行测试,所以您需要**自行测试**。 + ## Star History @@ -108,7 +108,8 @@ curl --location 'http://localhost:9000/translate' --header 'Content-Type: applic -## 鸣谢 +## Acknowledgments | 鸣谢 + 1. [OwO-Network/DeepLX](https://github.com/OwO-Network/DeepLX) 2. [LegendLeo/deeplx-serverless](https://github.com/LegendLeo/deeplx-serverless) 3. [bropines/Deeplx-vercel](https://github.com/bropines/Deeplx-vercel) diff --git a/api/index.js b/api/index.js index d518443..1473f75 100644 --- a/api/index.js +++ b/api/index.js @@ -1,65 +1,16 @@ -const express = require('express'); -const bodyParser = require('body-parser'); -const { translate } = require('../translate'); +import express from 'express'; +import fetch from 'node-fetch'; +import { post, get } from '../server.js'; const app = express(); -const PORT = 9000; -const allowAlternative = true; - -app.use(bodyParser.json()); app.post('/translate', async (req, res) => { - const startTime = Date.now(); // 记录开始时间 - - // 检查请求方法和请求体 - if (req.method !== 'POST' || !req.body || !req.body.text) { - const duration = Date.now() - startTime; - console.log(`[LOG] ${new Date().toISOString()} | 404 | ${duration}ms | POST "translate"`); - return res.status(404).json({ - "code": 404, - "message": "Path not found" - }); - } - - if (!allowAlternative) alternative_number = 0; - const { text, source_lang, target_lang, alternative_number } = req.body; - - try { - const result = await translate(text, source_lang, target_lang, alternative_number); - const duration = Date.now() - startTime; // 计算处理时间 - console.log(`[LOG] ${new Date().toISOString()} | 200 | ${duration}ms | POST "translate"`); + // 转发请求 + const response = await post(req, res); - const responseData = { - code: 200, - data: result.text, // 取第一个翻译结果 - id: Math.floor(Math.random() * 10000000000), // 生成一个随机 ID - method: 'Free', - source_lang, - target_lang, - alternatives: result.alternatives - }; - - res.json(responseData); - } catch (error) { - const duration = Date.now() - startTime; - console.error(`[ERROR] ${new Date().toISOString()} | 500 | ${duration}ms | POST "translate" | ${error.message}`); - res.status(500).json({ - code: 500, - message: 'Translation failed', - error: error.message - }); - } -}); - -// -app.get('/', (req, res) => { - res.json({ - code: 200, - message: "Welcome to the DeepL Free API. Please POST to '/translate'. Visit 'https://github.com/OwO-Network/DeepLX' and 'https://github.com/guobao/DeepLX-Serverless' for more information." - }); + // 返回响应 + const data = await response.json(); + res.status(response.status).json(data); }); -// 启动本地服务器 -app.listen(PORT, () => { - console.log(`Server is running on http://localhost:${PORT}`); -}); +app.get('/', async (req, res) => await get(req, res)); \ No newline at end of file diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..c98945c --- /dev/null +++ b/netlify.toml @@ -0,0 +1,2 @@ +[build] + command = "npm install" diff --git a/package.json b/package.json index f3cd839..b753ebc 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,13 @@ "name": "deeplx-serverless", "version": "1.0.0", "description": "DeepLX Free API for serverless", + "type": "module", "main": "translate.js", + "engines": { + "node": ">=16.13" + }, "scripts": { - "start": "node api/index.js", + "start": "node server.js", "test": "node test.js" }, "keywords": [ @@ -19,6 +23,7 @@ "body-parser": "^1.20.2", "express": "^4.18.2", "lodash": "^4.17.21", + "node-fetch": "^3.3.2", "random-int": "^3.0.0" } } diff --git a/server.js b/server.js new file mode 100644 index 0000000..9f8ee58 --- /dev/null +++ b/server.js @@ -0,0 +1,70 @@ +import express from 'express'; +import bodyParser from 'body-parser'; +import { translate } from './translate.js'; + +const app = express(); +const PORT = 9000; +const allowAlternative = true; + +app.use(bodyParser.json()); +// 为了方便兼容多平台才这样写 +app.post('/translate', async (req, res) => await post(req, res)); +app.get('/', async (req, res) => await get(req, res)); + +async function post(req, res) { + const startTime = Date.now(); // 记录开始时间 + + // 检查请求方法和请求体 + if (req.method !== 'POST' || !req.body || !req.body.text) { + const duration = Date.now() - startTime; + console.log(`[LOG] ${new Date().toISOString()} | 404 | ${duration}ms | POST "translate"`); + return res.status(404).json({ + "code": 404, + "message": "Path not found" + }); + } + + // 判断是否备选翻译 + if (!allowAlternative) alt_count = 0; + const { text, source_lang, target_lang, alt_count } = req.body; + + try { + const result = await translate(text, source_lang, target_lang, alt_count); + const duration = Date.now() - startTime; // 计算处理时间 + console.log(`[LOG] ${new Date().toISOString()} | 200 | ${duration}ms | POST "translate"`); + + const responseData = { + code: 200, + data: result.text, // 取第一个翻译结果 + id: Math.floor(Math.random() * 10000000000), // 生成一个随机 ID + method: 'Free', + source_lang, + target_lang, + alternatives: result.alternatives + }; + + res.json(responseData); + } catch (error) { + const duration = Date.now() - startTime; + console.error(`[ERROR] ${new Date().toISOString()} | 500 | ${duration}ms | POST "translate" | ${error.message}`); + res.status(500).json({ + code: 500, + message: 'Translation failed', + error: error.message + }); + } +}; + +async function get(req, res) { + res.json({ + code: 200, + message: "Welcome to the DeepL Free API. Please POST to '/translate'. Visit 'https://github.com/OwO-Network/DeepLX' and 'https://github.com/guobao2333/DeepLX-Serverless' for more information." + }); +}; + +// 启动本地服务器 +app.listen(PORT, () => { + console.log(`Server is running on http://localhost:${PORT}`); +}); + +export { post, get }; \ No newline at end of file diff --git a/test.js b/test.js index 951f690..9322f30 100644 --- a/test.js +++ b/test.js @@ -1,8 +1,7 @@ -const { translate } = require('./translate'); +import { translate } from './translate.js'; (async () => { // Example Call await translate('各位评委好,我是练习时长两年半的个人练习生,蔡徐坤', 'ZH', 'EN', 3, true); console.log('\n'); - await translate('鸡你太美,baby,鸡你实在是太美,baby', 'ZH', 'EN', 0, true) })() diff --git a/translate.js b/translate.js index 14463b6..3437f50 100644 --- a/translate.js +++ b/translate.js @@ -1,6 +1,7 @@ -const axios = require('axios').default; -const { random } = require('lodash'); +import axios from 'axios'; +import lodash from 'lodash'; +const { random } = lodash; const DEEPL_BASE_URL = 'https://www2.deepl.com/jsonrpc'; const headers = { 'Content-Type': 'application/json', @@ -37,20 +38,20 @@ async function translate( text, sourceLang = 'AUTO', targetLang = 'ZH', - alternativeNumber = 0, + alternativeCount = 0, printResult = false, ) { const iCount = getICount(text); const id = getRandomNumber(); - alternativeNumber = Math.max(Math.min(3, alternativeNumber), 0); + alternativeCount = Math.max(Math.min(3, alternativeCount), 0); const postData = { jsonrpc: '2.0', method: 'LMT_handle_texts', id: id, params: { - texts: [{ text: text, requestAlternatives: alternativeNumber }], + texts: [{ text: text, requestAlternatives: alternativeCount }], splitting: 'newlines', lang: { source_lang_user_selected: sourceLang.toUpperCase(), @@ -97,4 +98,4 @@ async function translate( } } -exports.translate = translate; +export { translate };