mirror of
https://github.com/OwO-Network/DeepLX.git
synced 2025-04-19 14:13:24 +00:00
Compare commits
77 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4cee0f3031 | ||
|
cbc3c1be51 | ||
|
84792ead81 | ||
|
0a9ff6b582 | ||
|
d1dbfcc1e5 | ||
|
2400139a8d | ||
|
26a9003b13 | ||
|
85fd738f3e | ||
|
de9888ca5f | ||
|
bbfb808793 | ||
|
4a77cbf30e | ||
|
2d8b84e2c8 | ||
|
1c8beb8a87 | ||
|
f2fa90208d | ||
|
b04139e89d | ||
|
44b6c2915f | ||
|
b89751f78f | ||
|
1f62d85b60 | ||
|
547c735b1f | ||
|
ede6229b0e | ||
|
d98f71d1c5 | ||
|
9edb997f06 | ||
|
62a993bb13 | ||
|
c678e87631 | ||
|
ac8ec23790 | ||
|
9e8c68fc94 | ||
|
1bef182a15 | ||
|
74cf2b9845 | ||
|
f172f59fb6 | ||
|
29ac0e1589 | ||
|
dce5ccd029 | ||
|
56755a1b92 | ||
|
a9a5a914b6 | ||
|
e9b5dedc43 | ||
|
0d73552773 | ||
|
7090eadfd5 | ||
|
f78de58337 | ||
|
8bf6d05603 | ||
|
93a3204eab | ||
|
eeeeeee684 | ||
|
3a4b1507d9 | ||
|
0b93569182 | ||
|
1dfc27518b | ||
|
b44e9b614d | ||
|
56c066a316 | ||
|
9ce414d6a2 | ||
|
a0b110681d | ||
|
7b50838f68 | ||
|
c954c65d0f | ||
|
401b5cb117 | ||
|
90d4d44fc0 | ||
|
e15e63b797 | ||
|
15cca97b81 | ||
|
7b97e65ec7 | ||
|
f75bfc20f7 | ||
|
a191d9d27f | ||
|
e580d64fbf | ||
|
7c4b521050 | ||
|
dedd87c3a8 | ||
|
9fff35f4fe | ||
|
aec7a29b12 | ||
|
41bba5e89f | ||
|
e286a732cb | ||
|
6db098eb8b | ||
|
fab55bfefa | ||
|
2055f022dc | ||
|
b85bb324e2 | ||
|
23693936cf | ||
|
7622b40986 | ||
|
9a3d8f8d75 | ||
|
55b1fccc48 | ||
|
e359bc7eec | ||
|
c965f54072 | ||
|
683b256760 | ||
|
fd1de8250a | ||
|
46087d017a | ||
|
9ca3249919 |
@ -2,8 +2,8 @@
|
||||
###
|
||||
# @Author: Vincent Young
|
||||
# @Date: 2022-10-20 02:19:06
|
||||
# @LastEditors: Vincent Young
|
||||
# @LastEditTime: 2023-02-18 20:45:52
|
||||
# @LastEditors: Vincent Yang
|
||||
# @LastEditTime: 2024-03-20 16:52:40
|
||||
# @FilePath: /DeepLX/.cross_compile.sh
|
||||
# @Telegram: https://t.me/missuo
|
||||
#
|
||||
@ -30,9 +30,9 @@ for pl in ${PLATFORMS}; do
|
||||
echo "build => ${TARGET}"
|
||||
if [ "${DEBUG_MODE}" == "debug" ]; then
|
||||
CGO_ENABLED=0 go build -trimpath -gcflags "all=-N -l" -o ${TARGET} \
|
||||
-ldflags "-w -s" main.go
|
||||
-ldflags "-w -s" .
|
||||
else
|
||||
CGO_ENABLED=0 go build -trimpath -o ${TARGET} \
|
||||
-ldflags "-w -s" main.go
|
||||
-ldflags "-w -s" .
|
||||
fi
|
||||
done
|
||||
|
2
.github/workflows/ci.yaml
vendored
2
.github/workflows/ci.yaml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: '1.19'
|
||||
go-version: '1.24.2'
|
||||
|
||||
- name: Install golint
|
||||
run: go install golang.org/x/lint/golint@latest
|
||||
|
5
.github/workflows/release.yaml
vendored
5
.github/workflows/release.yaml
vendored
@ -9,13 +9,13 @@ jobs:
|
||||
|
||||
Build:
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
runs-on: self-hosted
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: "1.19"
|
||||
go-version: "1.24.2"
|
||||
|
||||
- run: bash .cross_compile.sh
|
||||
|
||||
@ -23,5 +23,6 @@ jobs:
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
draft: false
|
||||
generate_release_notes: true
|
||||
files: |
|
||||
dist/*
|
||||
|
@ -1,10 +1,6 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM golang:1.19 AS builder
|
||||
FROM golang:1.24.2 AS builder
|
||||
WORKDIR /go/src/github.com/OwO-Network/DeepLX
|
||||
COPY main.go ./
|
||||
COPY go.mod ./
|
||||
COPY go.sum ./
|
||||
COPY . .
|
||||
RUN go get -d -v ./
|
||||
RUN CGO_ENABLED=0 go build -a -installsuffix cgo -o deeplx .
|
||||
|
||||
|
199
README.md
199
README.md
@ -1,8 +1,8 @@
|
||||
<!--
|
||||
* @Author: Vincent Young
|
||||
* @Date: 2022-10-18 07:32:29
|
||||
* @LastEditors: Vincent Young
|
||||
* @LastEditTime: 2023-11-28 00:24:20
|
||||
* @LastEditors: Vincent Yang
|
||||
* @LastEditTime: 2024-11-30 19:48:00
|
||||
* @FilePath: /DeepLX/README.md
|
||||
* @Telegram: https://t.me/missuo
|
||||
*
|
||||
@ -12,195 +12,36 @@
|
||||
[![GitHub Workflow][1]](https://github.com/OwO-Network/DeepLX/actions)
|
||||
[![Go Version][2]](https://github.com/OwO-Network/DeepLX/blob/main/go.mod)
|
||||
[![Go Report][3]](https://goreportcard.com/badge/github.com/OwO-Network/DeepLX)
|
||||
[![Maintainability][4]](https://codeclimate.com/github/OwO-Network/DeepLX/maintainability)
|
||||
[![GitHub License][5]](https://github.com/OwO-Network/DeepLX/blob/main/LICENSE)
|
||||
[![Docker Pulls][6]](https://hub.docker.com/r/missuo/deeplx)
|
||||
[![Releases][7]](https://github.com/OwO-Network/DeepLX/releases)
|
||||
[![GitHub License][4]](https://github.com/OwO-Network/DeepLX/blob/main/LICENSE)
|
||||
[![Docker Pulls][5]](https://hub.docker.com/r/missuo/deeplx)
|
||||
[![Releases][6]](https://github.com/OwO-Network/DeepLX/releases)
|
||||
|
||||
[1]: https://img.shields.io/github/actions/workflow/status/OwO-Network/DeepLX/release.yaml?logo=github
|
||||
[2]: https://img.shields.io/github/go-mod/go-version/OwO-Network/DeepLX?logo=go
|
||||
[3]: https://goreportcard.com/badge/github.com/OwO-Network/DeepLX
|
||||
[4]: https://api.codeclimate.com/v1/badges/b5b30239174fc6603aca/maintainability
|
||||
[5]: https://img.shields.io/github/license/OwO-Network/DeepLX
|
||||
[6]: https://img.shields.io/docker/pulls/missuo/deeplx?logo=docker
|
||||
[7]: https://img.shields.io/github/v/release/OwO-Network/DeepLX?logo=smartthings
|
||||
[4]: https://img.shields.io/github/license/OwO-Network/DeepLX
|
||||
[5]: https://img.shields.io/docker/pulls/missuo/deeplx?logo=docker
|
||||
[6]: https://img.shields.io/github/v/release/OwO-Network/DeepLX?logo=smartthings
|
||||
|
||||
## **Related Projects**
|
||||
| Link | Description | Maintainer |
|
||||
| ------------------------------------------ | -------------------------------------- | ----------------- |
|
||||
| [OwO-Network/PyDeepLX](https://github.com/OwO-Network/PyDeepLX) | Python Package for DeepLX | [Vincent Yang](https://github.com/missuo) |
|
||||
| [OwO-Network/gdeeplx](https://github.com/OwO-Network/gdeeplx) | Golang Package for DeepLX | [Vincent Yang](https://github.com/missuo) |
|
||||
| [ifyour/deeplx](https://github.com/ifyour/deeplx) | JS Package for DeepLX (JavaScript) | [ifyour](https://github.com/ifyour) |
|
||||
## How to use
|
||||
|
||||
> \[!TIP]
|
||||
>
|
||||
> Learn more about [📘 Using DeepLX](https://deeplx.owo.network) by checking it out.
|
||||
|
||||
## Discussion Group
|
||||
[Telegram Group](https://t.me/+8KDGHKJCxEVkNzll)
|
||||
|
||||
## Description
|
||||
- `DeepLX` is listening to `0.0.0.0:1188` by default. You can modify the listening port by yourself.
|
||||
- `DeepLX` is using `DeepL` Free API.
|
||||
- `DeepLX` is unlimited to the number of requests.
|
||||
## Acknowledgements
|
||||
|
||||
## Usage
|
||||
### For Developer
|
||||
#### Request Parameters
|
||||
- text: string
|
||||
- source_lang: string
|
||||
- target_lang: string
|
||||
### Contributors
|
||||
|
||||
#### Response
|
||||
```json
|
||||
{
|
||||
"alternatives": [
|
||||
"Did you hear about this?",
|
||||
"You've heard about this?",
|
||||
"You've heard of this?"
|
||||
],
|
||||
"code": 200,
|
||||
"data": "Have you heard about this?",
|
||||
"id": 8356681003,
|
||||
"method": "Free",
|
||||
"source_lang": "ZH",
|
||||
"target_lang": "EN"
|
||||
}
|
||||
```
|
||||
### Custom Options
|
||||
**The following settings are optional and not required.**
|
||||
- `-port` or `-p` : Listening port. Default is `1188`.
|
||||
- `-token` : Access token. If you have set it up, each request will need to include an `Authorization` header.
|
||||
- `-authkey` : DeepL Official `AuthKey`. If you have set it up, after the 429 response, the official AuthKey will be used for the request. If multiple authKeys are used simultaneously, they need to be separated by commas.
|
||||
<a href="https://github.com/OwO-Network/DeepLX/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=OwO-Network/DeepLX&anon=0" />
|
||||
</a>
|
||||
|
||||
#### Requesting a token-protected **DeepLX API** instance using the `curl`
|
||||
```
|
||||
curl -X POST http://localhost:1188/translate \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer your_access_token" \
|
||||
-d '{
|
||||
"text": "Hello, world!",
|
||||
"source_lang": "EN",
|
||||
"target_lang": "DE"
|
||||
}'
|
||||
```
|
||||
|
||||
### Run with Docker
|
||||
```bash
|
||||
# ghcr.io
|
||||
docker run -itd -p 1188:1188 ghcr.io/owo-network/deeplx:latest
|
||||
|
||||
# custom environment variables
|
||||
docker run -itd -p 1188:1188 -e "TOKEN=helloxxx" -e "AUTHKEY=xxxx:fx" ghcr.io/owo-network/deeplx:latest
|
||||
|
||||
# dockerhub
|
||||
docker run -itd -p 1188:1188 missuo/deeplx:latest
|
||||
|
||||
# custom environment variables
|
||||
docker run -itd -p 1188:1188 -e "TOKEN=helloxxx" -e "AUTHKEY=xxxx:fx" missuo/deeplx:latest
|
||||
```
|
||||
|
||||
### Run with Docker Compose
|
||||
```bash
|
||||
mkdir deeplx
|
||||
cd deeplx
|
||||
wget https://raw.githubusercontent.com/OwO-Network/DeepLX/main/compose.yaml
|
||||
# modify environment variables
|
||||
# environment:
|
||||
# - TOKEN=helloxxx
|
||||
# - AUTHKEY=xxxxxxx:fx
|
||||
# docker compose
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### Run on Linux Server
|
||||
```bash
|
||||
bash <(curl -Ls https://raw.githubusercontent.com/OwO-Network/DeepLX/main/install.sh)
|
||||
# or
|
||||
bash <(curl -Ls https://qwq.mx/deeplx)
|
||||
```
|
||||
|
||||
### Run on Mac
|
||||
#### Homebrew (Recommended)
|
||||
**Homebrew has been fixed in the latest version and works perfectly.**
|
||||
```bash
|
||||
brew tap owo-network/brew
|
||||
brew install deeplx
|
||||
brew services start owo-network/brew/deeplx
|
||||
|
||||
# Update to the latest version
|
||||
brew update
|
||||
brew upgrade deeplx
|
||||
brew services restart owo-network/brew/deeplx
|
||||
|
||||
# View the currently installed version
|
||||
brew list --versions deeplx
|
||||
```
|
||||
|
||||
#### Manual
|
||||
1. Download the latest release of DeepL X.
|
||||
```bash
|
||||
sudo mv deeplx_darwin_amd64 /usr/local/bin/deeplx
|
||||
sudo chmod +x /usr/local/bin/deeplx
|
||||
```
|
||||
|
||||
2. Download the `me.missuo.deeplx.plist` to `~/Library/LaunchAgents`.
|
||||
```bash
|
||||
wget https://raw.githubusercontent.com/OwO-Network/DeepLX/main/me.missuo.deeplx.plist -O ~/Library/LaunchAgents/me.missuo.deeplx.plist
|
||||
```
|
||||
3. Run following command.
|
||||
```bash
|
||||
launchctl load ~/Library/LaunchAgents/me.missuo.deeplx.plist
|
||||
launchctl start ~/Library/LaunchAgents/me.missuo.deeplx.plist
|
||||
```
|
||||
|
||||
### Install from AUR
|
||||
```bash
|
||||
paru -S deeplx-bin
|
||||
```
|
||||
|
||||
After installation, start the daemon with the following command.
|
||||
|
||||
```bash
|
||||
systemctl daemon-reload
|
||||
systemctl enable deeplx
|
||||
|
||||
```
|
||||
## Setup on [Bob App](https://bobtranslate.com/)
|
||||
1. Install [bob-plugin-deeplx](https://github.com/missuo/bob-plugin-deeplx) on Bob.
|
||||
|
||||
2. Setup the API. (If you use Brew to install locally you can skip this step)
|
||||

|
||||
|
||||
## Setup on [immersive-translate](https://github.com/immersive-translate/immersive-translate)
|
||||
**It is not recommended, because the `immersive-translate` will send many requests in a short time, which will cause the `DeepL API` to block your IP.**
|
||||
|
||||
1. Install Latest [immersive-translate ](https://github.com/immersive-translate/immersive-translate/releases) on your browser.
|
||||
|
||||
2. Click on **Developer Settings** in the bottom left corner. **Enable Beta experimental features**.
|
||||
|
||||
3. Set the URL. (If you are not deploying locally, you need to change 127.0.0.1 to the IP of your server)
|
||||
|
||||

|
||||
|
||||
## Use in Python
|
||||
```python
|
||||
import httpx, json
|
||||
|
||||
deeplx_api = "http://127.0.0.1:1188/translate"
|
||||
|
||||
data = {
|
||||
"text": "Hello World",
|
||||
"source_lang": "EN",
|
||||
"target_lang": "ZH"
|
||||
}
|
||||
|
||||
post_data = json.dumps(data)
|
||||
r = httpx.post(url = deeplx_api, data = post_data).text
|
||||
print(r)
|
||||
```
|
||||
|
||||
## Backup the Docker Image of zu1k
|
||||
```shell
|
||||
docker run -itd -p 1188:80 missuo/deeplx-bk
|
||||
```
|
||||
**This docker image is not related to this project, as the original author deleted the image, it is only for backup.**
|
||||
## Activity
|
||||

|
||||
|
||||
## License
|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2FOwO-Network%2FDeepLX?ref=badge_large)
|
||||
|
@ -1,5 +1,3 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
deeplx:
|
||||
image: ghcr.io/owo-network/deeplx:latest
|
||||
@ -8,4 +6,4 @@ services:
|
||||
- "1188:1188"
|
||||
# environment:
|
||||
# - TOKEN=helloworld
|
||||
# - AUTHKEY=xxxxxxx:fx
|
||||
# - DL_SESSION=xxxxxx
|
||||
|
54
go.mod
54
go.mod
@ -1,40 +1,58 @@
|
||||
module github.com/OwO-Network/DeepLX
|
||||
|
||||
go 1.19
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/abadojack/whatlanggo v1.0.1
|
||||
github.com/andybalholm/brotli v1.0.5
|
||||
github.com/gin-contrib/cors v1.4.0
|
||||
github.com/andybalholm/brotli v1.1.0
|
||||
github.com/gin-contrib/cors v1.6.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/imroc/req/v3 v3.48.0
|
||||
github.com/tidwall/gjson v1.14.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/bytedance/sonic v1.11.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||
github.com/cloudflare/circl v1.4.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.19.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.48.2 // indirect
|
||||
github.com/refraction-networking/utls v1.6.7 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sys v0.13.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.uber.org/mock v0.4.0 // indirect
|
||||
golang.org/x/arch v0.7.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
|
||||
golang.org/x/mod v0.21.0 // indirect
|
||||
golang.org/x/net v0.36.0 // indirect
|
||||
golang.org/x/sync v0.11.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/tools v0.25.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
162
go.sum
162
go.sum
@ -1,89 +1,106 @@
|
||||
github.com/abadojack/whatlanggo v1.0.1 h1:19N6YogDnf71CTHm3Mp2qhYfkRdyvbgwWdd2EPxJRG4=
|
||||
github.com/abadojack/whatlanggo v1.0.1/go.mod h1:66WiQbSbJBIlOZMsvbKe5m6pzQovxCH9B/K8tQB2uoc=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
|
||||
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.11.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A=
|
||||
github.com/bytedance/sonic v1.11.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
||||
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/cloudflare/circl v1.4.0 h1:BV7h5MgrktNzytKmWjpOtdYrf0lkkbF8YMlBGPhJQrY=
|
||||
github.com/cloudflare/circl v1.4.0/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
|
||||
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gin-contrib/cors v1.6.0 h1:0Z7D/bVhE6ja07lI8CTjTonp6SB07o8bNuFyRbsBUQg=
|
||||
github.com/gin-contrib/cors v1.6.0/go.mod h1:cI+h6iOAyxKRtUtC6iF/Si1KSFvGm/gK+kshxlCi8ro=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
|
||||
github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134 h1:c5FlPPgxOn7kJz3VoPLkQYQXGBS3EklQ4Zfi57uOuqQ=
|
||||
github.com/google/pprof v0.0.0-20240910150728-a0b0bb1d4134/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
|
||||
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
|
||||
github.com/imroc/req/v3 v3.48.0 h1:IYuMGetuwLzOOTzDCquDqs912WNwpsPK0TBXWPIvoqg=
|
||||
github.com/imroc/req/v3 v3.48.0/go.mod h1:weam9gmyb00QnOtu6HXSnk44dNFkIUQb5QdMx13FeUU=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
|
||||
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.48.2 h1:wsKXZPeGWpMpCGSWqOcqpW2wZYic/8T3aqiOID0/KWE=
|
||||
github.com/quic-go/quic-go v0.48.2/go.mod h1:yBgs3rWBOADpga7F+jJsb6Ybg1LSYiQvwWlLX+/6HMs=
|
||||
github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM=
|
||||
github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
|
||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw=
|
||||
github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
@ -92,47 +109,40 @@ github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||
golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
|
||||
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
|
||||
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
|
||||
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
|
||||
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
BIN
img/6a48ba28621f2465028f0.png
Normal file
BIN
img/6a48ba28621f2465028f0.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 287 KiB |
BIN
img/c5c19dd89df6fae1a256d.png
Normal file
BIN
img/c5c19dd89df6fae1a256d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 592 KiB |
436
main.go
436
main.go
@ -1,448 +1,34 @@
|
||||
/*
|
||||
* @Author: Vincent Young
|
||||
* @Author: Vincent Yang
|
||||
* @Date: 2023-07-01 21:45:34
|
||||
* @LastEditors: Vincent Young
|
||||
* @LastEditTime: 2023-11-28 00:23:42
|
||||
* @LastEditors: Jason Lyu
|
||||
* @LastEditTime: 2025-04-08 13:45:00
|
||||
* @FilePath: /DeepLX/main.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
*
|
||||
* Copyright © 2023 by Vincent, All Rights Reserved.
|
||||
* Copyright © 2024 by Vincent, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/abadojack/whatlanggo"
|
||||
"github.com/andybalholm/brotli"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/tidwall/gjson"
|
||||
|
||||
"github.com/OwO-Network/DeepLX/service"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Port int
|
||||
Token string
|
||||
AuthKey string
|
||||
}
|
||||
|
||||
func InitConfig() *Config {
|
||||
cfg := &Config{
|
||||
Port: 1188,
|
||||
}
|
||||
|
||||
flag.IntVar(&cfg.Port, "port", cfg.Port, "set up the port to listen on")
|
||||
flag.IntVar(&cfg.Port, "p", cfg.Port, "set up the port to listen on")
|
||||
|
||||
flag.StringVar(&cfg.Token, "token", "", "set the access token for /translate endpoint")
|
||||
if cfg.Token == "" {
|
||||
if token, ok := os.LookupEnv("TOKEN"); ok {
|
||||
cfg.Token = token
|
||||
}
|
||||
}
|
||||
|
||||
flag.StringVar(&cfg.AuthKey, "authkey", "", "The authentication key for DeepL API")
|
||||
if cfg.AuthKey == "" {
|
||||
if authKey, ok := os.LookupEnv("AUTHKEY"); ok {
|
||||
cfg.AuthKey = authKey
|
||||
}
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
return cfg
|
||||
}
|
||||
|
||||
type Lang struct {
|
||||
SourceLangUserSelected string `json:"source_lang_user_selected"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
}
|
||||
|
||||
type CommonJobParams struct {
|
||||
WasSpoken bool `json:"wasSpoken"`
|
||||
TranscribeAS string `json:"transcribe_as"`
|
||||
// RegionalVariant string `json:"regionalVariant"`
|
||||
}
|
||||
|
||||
type Params struct {
|
||||
Texts []Text `json:"texts"`
|
||||
Splitting string `json:"splitting"`
|
||||
Lang Lang `json:"lang"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
CommonJobParams CommonJobParams `json:"commonJobParams"`
|
||||
}
|
||||
|
||||
type Text struct {
|
||||
Text string `json:"text"`
|
||||
RequestAlternatives int `json:"requestAlternatives"`
|
||||
}
|
||||
|
||||
type PostData struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Method string `json:"method"`
|
||||
ID int64 `json:"id"`
|
||||
Params Params `json:"params"`
|
||||
}
|
||||
|
||||
func initData(sourceLang string, targetLang string) *PostData {
|
||||
return &PostData{
|
||||
Jsonrpc: "2.0",
|
||||
Method: "LMT_handle_texts",
|
||||
Params: Params{
|
||||
Splitting: "newlines",
|
||||
Lang: Lang{
|
||||
SourceLangUserSelected: sourceLang,
|
||||
TargetLang: targetLang,
|
||||
},
|
||||
CommonJobParams: CommonJobParams{
|
||||
WasSpoken: false,
|
||||
TranscribeAS: "",
|
||||
// RegionalVariant: "en-US",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getICount(translateText string) int64 {
|
||||
return int64(strings.Count(translateText, "i"))
|
||||
}
|
||||
|
||||
func getRandomNumber() int64 {
|
||||
rand.Seed(time.Now().Unix())
|
||||
num := rand.Int63n(99999) + 8300000
|
||||
return num * 1000
|
||||
}
|
||||
|
||||
func getTimeStamp(iCount int64) int64 {
|
||||
ts := time.Now().UnixMilli()
|
||||
if iCount != 0 {
|
||||
iCount = iCount + 1
|
||||
return ts - ts%iCount + iCount
|
||||
} else {
|
||||
return ts
|
||||
}
|
||||
}
|
||||
|
||||
type PayloadFree struct {
|
||||
TransText string `json:"text"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
}
|
||||
|
||||
type PayloadAPI struct {
|
||||
Text []string `json:"text"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
}
|
||||
|
||||
type Translation struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type TranslationResponse struct {
|
||||
Translations []Translation `json:"translations"`
|
||||
}
|
||||
|
||||
func translateByAPI(text string, targetLang string, sourceLang string, authKey string) (string, error) {
|
||||
url := "https://api-free.deepl.com/v2/translate"
|
||||
textArray := strings.Split(text, "\n")
|
||||
|
||||
payload := PayloadAPI{
|
||||
Text: textArray,
|
||||
TargetLang: targetLang,
|
||||
SourceLang: sourceLang,
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(payloadBytes))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
req.Header.Set("Authorization", "DeepL-Auth-Key "+authKey)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Parsing the response
|
||||
var translationResponse TranslationResponse
|
||||
err = json.Unmarshal(body, &translationResponse)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Concatenating the translations
|
||||
var sb strings.Builder
|
||||
for _, translation := range translationResponse.Translations {
|
||||
sb.WriteString(translation.Text)
|
||||
}
|
||||
|
||||
return sb.String(), nil
|
||||
}
|
||||
|
||||
type DeepLResponse struct {
|
||||
CharacterCount int `json:"character_count"`
|
||||
CharacterLimit int `json:"character_limit"`
|
||||
}
|
||||
|
||||
func checkUsage(authKey string) (bool, error) {
|
||||
url := "https://api-free.deepl.com/v2/usage"
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
req.Header.Add("Authorization", "DeepL-Auth-Key "+authKey)
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
var response DeepLResponse
|
||||
err = json.Unmarshal(body, &response)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return response.CharacterCount < 499900, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := InitConfig()
|
||||
cfg := service.InitConfig()
|
||||
|
||||
fmt.Printf("DeepL X has been successfully launched! Listening on 0.0.0.0:%v\n", cfg.Port)
|
||||
fmt.Printf("DeepL X has been successfully launched! Listening on %v:%v\n", cfg.IP, cfg.Port)
|
||||
fmt.Println("Developed by sjlleo <i@leo.moe> and missuo <me@missuo.me>.")
|
||||
|
||||
if cfg.Token != "" {
|
||||
fmt.Println("Access token is set.")
|
||||
}
|
||||
if cfg.AuthKey != "" {
|
||||
fmt.Println("DeepL Official Authentication key is set.")
|
||||
}
|
||||
|
||||
// Generating a random ID
|
||||
id := getRandomNumber()
|
||||
|
||||
// Setting the application to release mode
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.Default()
|
||||
r.Use(cors.Default())
|
||||
|
||||
// Defining the root endpoint which returns the project details
|
||||
r.GET("/", func(c *gin.Context) {
|
||||
c.JSON(200, gin.H{
|
||||
"code": 200,
|
||||
"message": "DeepL Free API, Developed by sjlleo and missuo. Go to /translate with POST. http://github.com/OwO-Network/DeepLX",
|
||||
})
|
||||
})
|
||||
|
||||
// Defining the translation endpoint which receives translation requests and returns translations
|
||||
r.POST("/translate", func(c *gin.Context) {
|
||||
req := PayloadFree{}
|
||||
c.BindJSON(&req)
|
||||
|
||||
if cfg.Token != "" {
|
||||
providedToken := c.GetHeader("Authorization")
|
||||
if providedToken != "Bearer "+cfg.Token {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "Invalid access token",
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Extracting details from the request JSON
|
||||
sourceLang := req.SourceLang
|
||||
targetLang := req.TargetLang
|
||||
translateText := req.TransText
|
||||
|
||||
// If source language is not specified, auto-detect it
|
||||
if sourceLang == "" {
|
||||
lang := whatlanggo.DetectLang(translateText)
|
||||
deepLLang := strings.ToUpper(lang.Iso6391())
|
||||
sourceLang = deepLLang
|
||||
}
|
||||
// If target language is not specified, set it to English
|
||||
if targetLang == "" {
|
||||
targetLang = "EN"
|
||||
}
|
||||
// Handling empty translation text
|
||||
if translateText == "" {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": http.StatusNotFound,
|
||||
"message": "No Translate Text Found",
|
||||
})
|
||||
return
|
||||
}
|
||||
// Preparing the request data for the DeepL API
|
||||
url := "https://www2.deepl.com/jsonrpc"
|
||||
id = id + 1
|
||||
postData := initData(sourceLang, targetLang)
|
||||
text := Text{
|
||||
Text: translateText,
|
||||
RequestAlternatives: 3,
|
||||
}
|
||||
postData.ID = id
|
||||
postData.Params.Texts = append(postData.Params.Texts, text)
|
||||
postData.Params.Timestamp = getTimeStamp(getICount(translateText))
|
||||
|
||||
// Marshalling the request data to JSON and making necessary string replacements
|
||||
post_byte, _ := json.Marshal(postData)
|
||||
postStr := string(post_byte)
|
||||
|
||||
// Adding spaces to the JSON string based on the ID to adhere to DeepL's request formatting rules
|
||||
if (id+5)%29 == 0 || (id+3)%13 == 0 {
|
||||
postStr = strings.Replace(postStr, "\"method\":\"", "\"method\" : \"", -1)
|
||||
} else {
|
||||
postStr = strings.Replace(postStr, "\"method\":\"", "\"method\": \"", -1)
|
||||
}
|
||||
|
||||
// Creating a new HTTP POST request with the JSON data as the body
|
||||
post_byte = []byte(postStr)
|
||||
reader := bytes.NewReader(post_byte)
|
||||
request, err := http.NewRequest("POST", url, reader)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
// Setting HTTP headers to mimic a request from the DeepL iOS App
|
||||
request.Header.Set("Content-Type", "application/json")
|
||||
request.Header.Set("Accept", "*/*")
|
||||
request.Header.Set("x-app-os-name", "iOS")
|
||||
request.Header.Set("x-app-os-version", "16.3.0")
|
||||
request.Header.Set("Accept-Language", "en-US,en;q=0.9")
|
||||
request.Header.Set("Accept-Encoding", "gzip, deflate, br")
|
||||
request.Header.Set("x-app-device", "iPhone13,2")
|
||||
request.Header.Set("User-Agent", "DeepL-iOS/2.9.1 iOS 16.3.0 (iPhone13,2)")
|
||||
request.Header.Set("x-app-build", "510265")
|
||||
request.Header.Set("x-app-version", "2.9.1")
|
||||
request.Header.Set("Connection", "keep-alive")
|
||||
|
||||
// Making the HTTP request to the DeepL API
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Handling potential Brotli compressed response body
|
||||
var bodyReader io.Reader
|
||||
switch resp.Header.Get("Content-Encoding") {
|
||||
case "br":
|
||||
bodyReader = brotli.NewReader(resp.Body)
|
||||
default:
|
||||
bodyReader = resp.Body
|
||||
}
|
||||
|
||||
// Reading the response body and parsing it with gjson
|
||||
body, err := io.ReadAll(bodyReader)
|
||||
// body, _ := io.ReadAll(resp.Body)
|
||||
res := gjson.ParseBytes(body)
|
||||
|
||||
// Handling various response statuses and potential errors
|
||||
if res.Get("error.code").String() == "-32600" {
|
||||
log.Println(res.Get("error").String())
|
||||
c.JSON(http.StatusNotAcceptable, gin.H{
|
||||
"code": http.StatusNotAcceptable,
|
||||
"message": "Invalid targetLang",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusTooManyRequests {
|
||||
authKeyArray := strings.Split(cfg.AuthKey, ",")
|
||||
for _, authKey := range authKeyArray {
|
||||
validity, err := checkUsage(authKey)
|
||||
if err != nil {
|
||||
continue
|
||||
} else {
|
||||
if validity == true {
|
||||
translatedText, err := translateByAPI(translateText, sourceLang, targetLang, authKey)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusTooManyRequests, gin.H{
|
||||
"code": http.StatusTooManyRequests,
|
||||
"message": "Too Many Requests",
|
||||
})
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"id": 1000000,
|
||||
"data": translatedText,
|
||||
"source_lang": sourceLang,
|
||||
"target_lang": targetLang,
|
||||
"method": "Official API",
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
var alternatives []string
|
||||
res.Get("result.texts.0.alternatives").ForEach(func(key, value gjson.Result) bool {
|
||||
alternatives = append(alternatives, value.Get("text").String())
|
||||
return true
|
||||
})
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"id": id,
|
||||
"data": res.Get("result.texts.0.text").String(),
|
||||
"alternatives": alternatives,
|
||||
"source_lang": sourceLang,
|
||||
"target_lang": targetLang,
|
||||
"method": "Free",
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Catch-all route to handle undefined paths
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": http.StatusNotFound,
|
||||
"message": "Path not found",
|
||||
})
|
||||
})
|
||||
|
||||
envPort, ok := os.LookupEnv("PORT")
|
||||
if ok {
|
||||
r.Run(":" + envPort)
|
||||
} else {
|
||||
r.Run(fmt.Sprintf(":%v", cfg.Port))
|
||||
}
|
||||
app := service.Router(cfg)
|
||||
app.Run(fmt.Sprintf("%v:%v", cfg.IP, cfg.Port))
|
||||
}
|
||||
|
75
service/config.go
Normal file
75
service/config.go
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* @Author: Vincent Yang
|
||||
* @Date: 2024-04-23 00:39:03
|
||||
* @LastEditors: Jason Lyu
|
||||
* @LastEditTime: 2025-04-08 13:45:00
|
||||
* @FilePath: /DeepLX/config.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
*
|
||||
* Copyright © 2024 by Vincent, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
IP string
|
||||
Port int
|
||||
Token string
|
||||
DlSession string
|
||||
Proxy string
|
||||
}
|
||||
|
||||
func InitConfig() *Config {
|
||||
cfg := &Config{
|
||||
IP: "0.0.0.0",
|
||||
Port: 1188,
|
||||
}
|
||||
|
||||
// IP flag
|
||||
if ip, ok := os.LookupEnv("IP"); ok && ip != "" {
|
||||
cfg.IP = ip
|
||||
}
|
||||
flag.StringVar(&cfg.IP, "ip", cfg.IP, "set up the IP address to bind to")
|
||||
flag.StringVar(&cfg.IP, "i", cfg.IP, "set up the IP address to bind to")
|
||||
|
||||
// Port flag
|
||||
if port, ok := os.LookupEnv("PORT"); ok && port != "" {
|
||||
fmt.Sscanf(port, "%d", &cfg.Port)
|
||||
}
|
||||
flag.IntVar(&cfg.Port, "port", cfg.Port, "set up the port to listen on")
|
||||
flag.IntVar(&cfg.Port, "p", cfg.Port, "set up the port to listen on")
|
||||
|
||||
// DL Session flag
|
||||
flag.StringVar(&cfg.DlSession, "s", "", "set the dl-session for /v1/translate endpoint")
|
||||
if cfg.DlSession == "" {
|
||||
if dlSession, ok := os.LookupEnv("DL_SESSION"); ok {
|
||||
cfg.DlSession = dlSession
|
||||
}
|
||||
}
|
||||
|
||||
// Access token flag
|
||||
flag.StringVar(&cfg.Token, "token", "", "set the access token for /translate endpoint")
|
||||
if cfg.Token == "" {
|
||||
if token, ok := os.LookupEnv("TOKEN"); ok {
|
||||
cfg.Token = token
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP Proxy flag
|
||||
flag.StringVar(&cfg.Proxy, "proxy", "", "set the proxy URL for HTTP requests")
|
||||
if cfg.Proxy == "" {
|
||||
if proxy, ok := os.LookupEnv("PROXY"); ok {
|
||||
cfg.Proxy = proxy
|
||||
}
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
return cfg
|
||||
}
|
275
service/service.go
Normal file
275
service/service.go
Normal file
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* @Author: Vincent Yang
|
||||
* @Date: 2023-07-01 21:45:34
|
||||
* @LastEditors: Jason Lyu
|
||||
* @LastEditTime: 2025-04-08 13:45:00
|
||||
* @FilePath: /DeepLX/main.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
*
|
||||
* Copyright © 2024 by Vincent, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/OwO-Network/DeepLX/translate"
|
||||
)
|
||||
|
||||
func authMiddleware(cfg *Config) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if cfg.Token != "" {
|
||||
providedTokenInQuery := c.Query("token")
|
||||
providedTokenInHeader := c.GetHeader("Authorization")
|
||||
|
||||
// Compatability with the Bearer token format
|
||||
if providedTokenInHeader != "" {
|
||||
parts := strings.Split(providedTokenInHeader, " ")
|
||||
if len(parts) == 2 {
|
||||
if parts[0] == "Bearer" || parts[0] == "DeepL-Auth-Key" {
|
||||
providedTokenInHeader = parts[1]
|
||||
} else {
|
||||
providedTokenInHeader = ""
|
||||
}
|
||||
} else {
|
||||
providedTokenInHeader = ""
|
||||
}
|
||||
}
|
||||
|
||||
if providedTokenInHeader != cfg.Token && providedTokenInQuery != cfg.Token {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "Invalid access token",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
type PayloadFree struct {
|
||||
TransText string `json:"text"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
TagHandling string `json:"tag_handling"`
|
||||
}
|
||||
|
||||
type PayloadAPI struct {
|
||||
Text []string `json:"text"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
TagHandling string `json:"tag_handling"`
|
||||
}
|
||||
|
||||
func Router(cfg *Config) *gin.Engine {
|
||||
// Set Proxy
|
||||
proxyURL := os.Getenv("PROXY")
|
||||
if proxyURL == "" {
|
||||
proxyURL = cfg.Proxy
|
||||
}
|
||||
if proxyURL != "" {
|
||||
proxy, err := url.Parse(proxyURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse proxy URL: %v", err)
|
||||
}
|
||||
http.DefaultTransport = &http.Transport{
|
||||
Proxy: http.ProxyURL(proxy),
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Token != "" {
|
||||
fmt.Println("Access token is set.")
|
||||
}
|
||||
|
||||
r := gin.Default()
|
||||
r.Use(cors.Default())
|
||||
|
||||
// Defining the root endpoint which returns the project details
|
||||
r.GET("/", func(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"message": "DeepL Free API, Developed by sjlleo and missuo. Go to /translate with POST. http://github.com/OwO-Network/DeepLX",
|
||||
})
|
||||
})
|
||||
|
||||
// Free API endpoint, No Pro Account required
|
||||
r.POST("/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
req := PayloadFree{}
|
||||
c.BindJSON(&req)
|
||||
|
||||
sourceLang := req.SourceLang
|
||||
targetLang := req.TargetLang
|
||||
translateText := req.TransText
|
||||
tagHandling := req.TagHandling
|
||||
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
if tagHandling != "" && tagHandling != "html" && tagHandling != "xml" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid tag_handling value. Allowed values are 'html' and 'xml'.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX(sourceLang, targetLang, translateText, tagHandling, proxyURL, "")
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"id": result.ID,
|
||||
"data": result.Data,
|
||||
"alternatives": result.Alternatives,
|
||||
"source_lang": result.SourceLang,
|
||||
"target_lang": result.TargetLang,
|
||||
"method": result.Method,
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// Pro API endpoint, Pro Account required
|
||||
r.POST("/v1/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
req := PayloadFree{}
|
||||
c.BindJSON(&req)
|
||||
|
||||
sourceLang := req.SourceLang
|
||||
targetLang := req.TargetLang
|
||||
translateText := req.TransText
|
||||
tagHandling := req.TagHandling
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
dlSession := cfg.DlSession
|
||||
|
||||
if tagHandling != "" && tagHandling != "html" && tagHandling != "xml" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid tag_handling value. Allowed values are 'html' and 'xml'.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
cookie := c.GetHeader("Cookie")
|
||||
if cookie != "" {
|
||||
dlSession = strings.Replace(cookie, "dl_session=", "", -1)
|
||||
}
|
||||
|
||||
if dlSession == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "No dl_session Found",
|
||||
})
|
||||
return
|
||||
} else if strings.Contains(dlSession, ".") {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{
|
||||
"code": http.StatusUnauthorized,
|
||||
"message": "Your account is not a Pro account. Please upgrade your account or switch to a different account.",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX(sourceLang, targetLang, translateText, tagHandling, proxyURL, dlSession)
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": http.StatusOK,
|
||||
"id": result.ID,
|
||||
"data": result.Data,
|
||||
"alternatives": result.Alternatives,
|
||||
"source_lang": result.SourceLang,
|
||||
"target_lang": result.TargetLang,
|
||||
"method": result.Method,
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
// Free API endpoint, Consistent with the official API format
|
||||
r.POST("/v2/translate", authMiddleware(cfg), func(c *gin.Context) {
|
||||
proxyURL := cfg.Proxy
|
||||
|
||||
var translateText string
|
||||
var targetLang string
|
||||
|
||||
translateText = c.PostForm("text")
|
||||
targetLang = c.PostForm("target_lang")
|
||||
|
||||
if translateText == "" || targetLang == "" {
|
||||
var jsonData struct {
|
||||
Text []string `json:"text"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
}
|
||||
|
||||
if err := c.BindJSON(&jsonData); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": http.StatusBadRequest,
|
||||
"message": "Invalid request payload",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
translateText = strings.Join(jsonData.Text, "\n")
|
||||
targetLang = jsonData.TargetLang
|
||||
}
|
||||
|
||||
result, err := translate.TranslateByDeepLX("", targetLang, translateText, "", proxyURL, "")
|
||||
if err != nil {
|
||||
log.Fatalf("Translation failed: %s", err)
|
||||
}
|
||||
|
||||
if result.Code == http.StatusOK {
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"translations": []map[string]interface{}{
|
||||
{
|
||||
"detected_source_language": result.SourceLang,
|
||||
"text": result.Data,
|
||||
},
|
||||
},
|
||||
})
|
||||
} else {
|
||||
c.JSON(result.Code, gin.H{
|
||||
"code": result.Code,
|
||||
"message": result.Message,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Catch-all route to handle undefined paths
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"code": http.StatusNotFound,
|
||||
"message": "Path not found",
|
||||
})
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
292
translate/translate.go
Normal file
292
translate/translate.go
Normal file
@ -0,0 +1,292 @@
|
||||
/*
|
||||
* @Author: Vincent Young
|
||||
* @Date: 2024-09-16 11:59:24
|
||||
* @LastEditors: Vincent Yang
|
||||
* @LastEditTime: 2025-04-08 14:26:33
|
||||
* @FilePath: /DeepLX/translate/translate.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
*
|
||||
* Copyright © 2024 by Vincent, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package translate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/abadojack/whatlanggo"
|
||||
"github.com/imroc/req/v3"
|
||||
|
||||
"github.com/andybalholm/brotli"
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
// makeRequest makes an HTTP request to DeepL API
|
||||
func makeRequest(postData *PostData, proxyURL string, dlSession string) (gjson.Result, error) {
|
||||
urlFull := "https://www2.deepl.com/jsonrpc"
|
||||
postStr := formatPostString(postData)
|
||||
|
||||
// Create a new req client
|
||||
client := req.C().SetTLSFingerprintRandomized()
|
||||
|
||||
// Set headers
|
||||
headers := http.Header{
|
||||
"Content-Type": []string{"application/json"},
|
||||
"User-Agent": []string{"DeepL/1627620 CFNetwork/3826.500.62.2.1 Darwin/24.4.0"},
|
||||
"Accept": []string{"*/*"},
|
||||
"X-App-Os-Name": []string{"iOS"},
|
||||
"X-App-Os-Version": []string{"18.4.0"},
|
||||
"Accept-Language": []string{"en-US,en;q=0.9"},
|
||||
"Accept-Encoding": []string{"gzip, deflate, br"}, // Keep this!
|
||||
"X-App-Device": []string{"iPhone16,2"},
|
||||
"Referer": []string{"https://www.deepl.com/"},
|
||||
"X-Product": []string{"translator"},
|
||||
"X-App-Build": []string{"1627620"},
|
||||
"X-App-Version": []string{"25.1"},
|
||||
}
|
||||
|
||||
if dlSession != "" {
|
||||
headers.Set("Cookie", "dl_session="+dlSession)
|
||||
}
|
||||
|
||||
// Set proxy if provided
|
||||
if proxyURL != "" {
|
||||
proxy, err := url.Parse(proxyURL)
|
||||
if err != nil {
|
||||
return gjson.Result{}, err
|
||||
}
|
||||
client.SetProxyURL(proxy.String())
|
||||
}
|
||||
|
||||
// Make the request
|
||||
r := client.R()
|
||||
r.Headers = headers
|
||||
resp, err := r.
|
||||
SetBody(bytes.NewReader([]byte(postStr))).
|
||||
Post(urlFull)
|
||||
|
||||
if err != nil {
|
||||
return gjson.Result{}, err
|
||||
}
|
||||
|
||||
var bodyReader io.Reader
|
||||
contentEncoding := resp.Header.Get("Content-Encoding")
|
||||
switch contentEncoding {
|
||||
case "br":
|
||||
bodyReader = brotli.NewReader(resp.Body)
|
||||
case "gzip":
|
||||
bodyReader, err = gzip.NewReader(resp.Body) // Use gzip.NewReader
|
||||
if err != nil {
|
||||
return gjson.Result{}, fmt.Errorf("failed to create gzip reader: %w", err)
|
||||
}
|
||||
case "deflate": // Less common, but good to handle
|
||||
bodyReader = flate.NewReader(resp.Body)
|
||||
default:
|
||||
bodyReader = resp.Body
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(bodyReader)
|
||||
if err != nil {
|
||||
return gjson.Result{}, fmt.Errorf("failed to read response body: %w", err)
|
||||
}
|
||||
return gjson.ParseBytes(body), nil
|
||||
}
|
||||
|
||||
// TranslateByDeepLX performs translation using DeepL API
|
||||
func TranslateByDeepLX(sourceLang, targetLang, text string, tagHandling string, proxyURL string, dlSession string) (DeepLXTranslationResult, error) {
|
||||
if text == "" {
|
||||
return DeepLXTranslationResult{
|
||||
Code: http.StatusNotFound,
|
||||
Message: "No text to translate",
|
||||
}, nil
|
||||
}
|
||||
|
||||
if tagHandling == "" {
|
||||
tagHandling = "plaintext"
|
||||
}
|
||||
|
||||
// Split text by newlines and store them for later reconstruction
|
||||
textParts := strings.Split(text, "\n")
|
||||
var translatedParts []string
|
||||
var allAlternatives [][]string // Store alternatives for each part
|
||||
|
||||
for _, part := range textParts {
|
||||
if strings.TrimSpace(part) == "" {
|
||||
translatedParts = append(translatedParts, "")
|
||||
allAlternatives = append(allAlternatives, []string{""})
|
||||
continue
|
||||
}
|
||||
|
||||
// Get detected language if source language is auto
|
||||
if sourceLang == "auto" || sourceLang == "" {
|
||||
sourceLang = strings.ToUpper(whatlanggo.DetectLang(part).Iso6391())
|
||||
}
|
||||
|
||||
// Prepare jobs from split result
|
||||
var jobs []Job
|
||||
|
||||
jobs = append(jobs, Job{
|
||||
Kind: "default",
|
||||
PreferredNumBeams: 4,
|
||||
RawEnContextBefore: []string{},
|
||||
RawEnContextAfter: []string{},
|
||||
Sentences: []Sentence{{
|
||||
Prefix: "",
|
||||
Text: text,
|
||||
ID: 0,
|
||||
}},
|
||||
})
|
||||
|
||||
hasRegionalVariant := false
|
||||
targetLangCode := targetLang
|
||||
targetLangParts := strings.Split(targetLang, "-")
|
||||
if len(targetLangParts) > 1 {
|
||||
targetLangCode = targetLangParts[0]
|
||||
hasRegionalVariant = true
|
||||
}
|
||||
|
||||
// Prepare translation request
|
||||
id := getRandomNumber()
|
||||
|
||||
postData := &PostData{
|
||||
Jsonrpc: "2.0",
|
||||
Method: "LMT_handle_jobs",
|
||||
ID: id,
|
||||
Params: Params{
|
||||
CommonJobParams: CommonJobParams{
|
||||
Mode: "translate",
|
||||
Formality: "undefined",
|
||||
TranscribeAs: "romanize",
|
||||
AdvancedMode: false,
|
||||
TextType: tagHandling,
|
||||
WasSpoken: false,
|
||||
},
|
||||
Lang: Lang{
|
||||
SourceLangUserSelected: "auto",
|
||||
TargetLang: strings.ToUpper(targetLangCode),
|
||||
SourceLangComputed: strings.ToUpper(sourceLang),
|
||||
},
|
||||
Jobs: jobs,
|
||||
Timestamp: getTimeStamp(getICount(part)),
|
||||
},
|
||||
}
|
||||
|
||||
if hasRegionalVariant {
|
||||
postData = &PostData{
|
||||
Jsonrpc: "2.0",
|
||||
Method: "LMT_handle_jobs",
|
||||
ID: id,
|
||||
Params: Params{
|
||||
CommonJobParams: CommonJobParams{
|
||||
Mode: "translate",
|
||||
Formality: "undefined",
|
||||
TranscribeAs: "romanize",
|
||||
AdvancedMode: false,
|
||||
TextType: tagHandling,
|
||||
WasSpoken: false,
|
||||
RegionalVariant: targetLang,
|
||||
},
|
||||
Lang: Lang{
|
||||
SourceLangUserSelected: "auto",
|
||||
TargetLang: strings.ToUpper(targetLangCode),
|
||||
SourceLangComputed: strings.ToUpper(sourceLang),
|
||||
},
|
||||
Jobs: jobs,
|
||||
Timestamp: getTimeStamp(getICount(part)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Make translation request
|
||||
result, err := makeRequest(postData, proxyURL, dlSession)
|
||||
if err != nil {
|
||||
return DeepLXTranslationResult{
|
||||
Code: http.StatusServiceUnavailable,
|
||||
Message: err.Error(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Process translation results
|
||||
var partTranslation string
|
||||
var partAlternatives []string
|
||||
|
||||
translations := result.Get("result.translations").Array()
|
||||
if len(translations) > 0 {
|
||||
// Process main translation
|
||||
for _, translation := range translations {
|
||||
partTranslation += translation.Get("beams.0.sentences.0.text").String() + " "
|
||||
}
|
||||
partTranslation = strings.TrimSpace(partTranslation)
|
||||
|
||||
// Process alternatives
|
||||
numBeams := len(translations[0].Get("beams").Array())
|
||||
for i := 1; i < numBeams; i++ { // Start from 1 since 0 is the main translation
|
||||
var altText string
|
||||
for _, translation := range translations {
|
||||
beams := translation.Get("beams").Array()
|
||||
if i < len(beams) {
|
||||
altText += beams[i].Get("sentences.0.text").String() + " "
|
||||
}
|
||||
}
|
||||
if altText != "" {
|
||||
partAlternatives = append(partAlternatives, strings.TrimSpace(altText))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if partTranslation == "" {
|
||||
return DeepLXTranslationResult{
|
||||
Code: http.StatusServiceUnavailable,
|
||||
Message: "Translation failed",
|
||||
}, nil
|
||||
}
|
||||
|
||||
translatedParts = append(translatedParts, partTranslation)
|
||||
allAlternatives = append(allAlternatives, partAlternatives)
|
||||
}
|
||||
|
||||
// Join all translated parts with newlines
|
||||
translatedText := strings.Join(translatedParts, "\n")
|
||||
|
||||
// Combine alternatives with proper newline handling
|
||||
var combinedAlternatives []string
|
||||
maxAlts := 0
|
||||
for _, alts := range allAlternatives {
|
||||
if len(alts) > maxAlts {
|
||||
maxAlts = len(alts)
|
||||
}
|
||||
}
|
||||
|
||||
// Create combined alternatives preserving line structure
|
||||
for i := 0; i < maxAlts; i++ {
|
||||
var altParts []string
|
||||
for j, alts := range allAlternatives {
|
||||
if i < len(alts) {
|
||||
altParts = append(altParts, alts[i])
|
||||
} else if len(translatedParts[j]) == 0 {
|
||||
altParts = append(altParts, "") // Keep empty lines
|
||||
} else {
|
||||
altParts = append(altParts, translatedParts[j]) // Use main translation if no alternative
|
||||
}
|
||||
}
|
||||
combinedAlternatives = append(combinedAlternatives, strings.Join(altParts, "\n"))
|
||||
}
|
||||
|
||||
return DeepLXTranslationResult{
|
||||
Code: http.StatusOK,
|
||||
ID: getRandomNumber(), // Using new ID for the complete translation
|
||||
Data: translatedText,
|
||||
Alternatives: combinedAlternatives,
|
||||
SourceLang: sourceLang,
|
||||
TargetLang: targetLang,
|
||||
Method: map[bool]string{true: "Pro", false: "Free"}[dlSession != ""],
|
||||
}, nil
|
||||
}
|
103
translate/types.go
Normal file
103
translate/types.go
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* @Author: Vincent Young
|
||||
* @Date: 2024-09-16 11:59:24
|
||||
* @LastEditors: Vincent Yang
|
||||
* @LastEditTime: 2025-03-01 04:16:07
|
||||
* @FilePath: /DeepLX/translate/types.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
*
|
||||
* Copyright © 2024 by Vincent, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package translate
|
||||
|
||||
// Lang represents the language settings for translation
|
||||
type Lang struct {
|
||||
SourceLangUserSelected string `json:"source_lang_user_selected"` // Can be "auto"
|
||||
TargetLang string `json:"target_lang"`
|
||||
SourceLangComputed string `json:"source_lang_computed,omitempty"`
|
||||
}
|
||||
|
||||
// CommonJobParams represents common parameters for translation jobs
|
||||
type CommonJobParams struct {
|
||||
Formality string `json:"formality"` // Can be "undefined"
|
||||
TranscribeAs string `json:"transcribe_as"`
|
||||
Mode string `json:"mode"`
|
||||
WasSpoken bool `json:"wasSpoken"`
|
||||
AdvancedMode bool `json:"advancedMode"`
|
||||
TextType string `json:"textType"`
|
||||
RegionalVariant string `json:"regionalVariant,omitempty"`
|
||||
}
|
||||
|
||||
// Sentence represents a sentence in the translation request
|
||||
type Sentence struct {
|
||||
Prefix string `json:"prefix"`
|
||||
Text string `json:"text"`
|
||||
ID int `json:"id"`
|
||||
}
|
||||
|
||||
// Job represents a translation job
|
||||
type Job struct {
|
||||
Kind string `json:"kind"`
|
||||
PreferredNumBeams int `json:"preferred_num_beams"`
|
||||
RawEnContextBefore []string `json:"raw_en_context_before"`
|
||||
RawEnContextAfter []string `json:"raw_en_context_after"`
|
||||
Sentences []Sentence `json:"sentences"`
|
||||
}
|
||||
|
||||
// Params represents parameters for translation requests
|
||||
type Params struct {
|
||||
CommonJobParams CommonJobParams `json:"commonJobParams"`
|
||||
Lang Lang `json:"lang"`
|
||||
Jobs []Job `json:"jobs"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// PostData represents the complete translation request
|
||||
type PostData struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
Method string `json:"method"`
|
||||
ID int64 `json:"id"`
|
||||
Params Params `json:"params"`
|
||||
}
|
||||
|
||||
// TranslationResponse represents the response from translation
|
||||
type TranslationResponse struct {
|
||||
Jsonrpc string `json:"jsonrpc"`
|
||||
ID int64 `json:"id"`
|
||||
Result struct {
|
||||
Translations []struct {
|
||||
Beams []struct {
|
||||
Sentences []SentenceResponse `json:"sentences"`
|
||||
NumSymbols int `json:"num_symbols"`
|
||||
RephraseVariant struct { // Added rephrase_variant
|
||||
Name string `json:"name"`
|
||||
} `json:"rephrase_variant"`
|
||||
} `json:"beams"`
|
||||
Quality string `json:"quality"` // Added quality
|
||||
} `json:"translations"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
SourceLang string `json:"source_lang"`
|
||||
SourceLangIsConfident bool `json:"source_lang_is_confident"`
|
||||
DetectedLanguages map[string]interface{} `json:"detectedLanguages"` // Use interface{} for now
|
||||
} `json:"result"`
|
||||
}
|
||||
|
||||
// SentenceResponse is a helper struct for the response sentences
|
||||
type SentenceResponse struct {
|
||||
Text string `json:"text"`
|
||||
IDS []int `json:"ids"` // Added IDS
|
||||
}
|
||||
|
||||
// DeepLXTranslationResult represents the final translation result
|
||||
type DeepLXTranslationResult struct {
|
||||
Code int `json:"code"`
|
||||
ID int64 `json:"id"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Data string `json:"data"` // The primary translated text
|
||||
Alternatives []string `json:"alternatives"` // Other possible translations
|
||||
SourceLang string `json:"source_lang"`
|
||||
TargetLang string `json:"target_lang"`
|
||||
Method string `json:"method"`
|
||||
}
|
57
translate/utils.go
Normal file
57
translate/utils.go
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* @Author: Vincent Young
|
||||
* @Date: 2024-09-16 11:59:24
|
||||
* @LastEditors: Vincent Yang
|
||||
* @LastEditTime: 2025-04-08 14:27:21
|
||||
* @FilePath: /DeepLX/translate/utils.go
|
||||
* @Telegram: https://t.me/missuo
|
||||
* @GitHub: https://github.com/missuo
|
||||
*
|
||||
* Copyright © 2024 by Vincent, All Rights Reserved.
|
||||
*/
|
||||
|
||||
package translate
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// getICount returns the number of 'i' characters in the text
|
||||
func getICount(translateText string) int64 {
|
||||
return int64(strings.Count(translateText, "i"))
|
||||
}
|
||||
|
||||
// getRandomNumber generates a random number for request ID
|
||||
func getRandomNumber() int64 {
|
||||
src := rand.NewSource(time.Now().UnixNano())
|
||||
rng := rand.New(src)
|
||||
num := rng.Int63n(99999) + 8300000
|
||||
return num * 1000
|
||||
}
|
||||
|
||||
// getTimeStamp generates timestamp for request based on i count
|
||||
func getTimeStamp(iCount int64) int64 {
|
||||
ts := time.Now().UnixMilli()
|
||||
if iCount != 0 {
|
||||
iCount = iCount + 1
|
||||
return ts - ts%iCount + iCount
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
// formatPostString formats the request JSON string with specific spacing rules
|
||||
func formatPostString(postData *PostData) string {
|
||||
postBytes, _ := json.Marshal(postData)
|
||||
postStr := string(postBytes)
|
||||
|
||||
if (postData.ID+5)%29 == 0 || (postData.ID+3)%13 == 0 {
|
||||
postStr = strings.Replace(postStr, `"method":"`, `"method" : "`, 1)
|
||||
} else {
|
||||
postStr = strings.Replace(postStr, `"method":"`, `"method": "`, 1)
|
||||
}
|
||||
|
||||
return postStr
|
||||
}
|
Loading…
Reference in New Issue
Block a user