Skip to content

Commit 84b543b

Browse files
committed
add caiyun translator
1 parent faf72bc commit 84b543b

File tree

6 files changed

+170
-3
lines changed

6 files changed

+170
-3
lines changed

caiyun.go

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package fy
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"encoding/base64"
7+
"encoding/json"
8+
"fmt"
9+
"net/http"
10+
"strings"
11+
12+
"github.com/google/uuid"
13+
"github.com/tidwall/gjson"
14+
)
15+
16+
type caiyunTranslator struct {
17+
token string
18+
seq1, seq2 string
19+
}
20+
21+
var caiyun translator = &caiyunTranslator{
22+
token: "token:qgemv4jr1y38jyq6vhvi",
23+
seq1: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
24+
seq2: "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm",
25+
}
26+
27+
func (b *caiyunTranslator) Desc() (string, string) {
28+
return "caiyun", "https://fanyi.caiyunapp.com"
29+
}
30+
31+
func CaiyunTranslate(ctx context.Context, req Request) *Response {
32+
return caiyun.translate(ctx, req)
33+
}
34+
35+
func (t *caiyunTranslator) translate(ctx context.Context, req Request) (resp *Response) {
36+
resp = newResp(t)
37+
req.ToLang, resp.Err = t.convertLanguage(req.ToLang)
38+
if resp.Err != nil {
39+
return
40+
}
41+
42+
browserId := strings.ReplaceAll(uuid.New().String(), "-", "")
43+
jwtBody := strings.NewReader(fmt.Sprintf(`{"browser_id":"%s"}`, browserId))
44+
45+
var jwtResponse struct {
46+
Rc int `json:"rc"`
47+
Jwt string `json:"jwt"`
48+
}
49+
50+
_, data, err := sendRequest(ctx, http.MethodPost, "https://api.interpreter.caiyunai.com/v1/user/jwt/generate", jwtBody, func(req *http.Request) error {
51+
req.Header.Set("Content-Type", "application/json")
52+
req.Header.Set("User-Agent", UserAgent)
53+
req.Header.Set("X-Authorization", t.token)
54+
return nil
55+
})
56+
if err := json.Unmarshal(data, &jwtResponse); err != nil {
57+
resp.Err = fmt.Errorf("get jwt error: %v", err)
58+
return
59+
}
60+
if jwtResponse.Rc != 0 {
61+
resp.Err = fmt.Errorf("unexpected jwt response: %s", string(data))
62+
return
63+
}
64+
65+
param := map[string]interface{}{
66+
"browser_id": browserId,
67+
"cached": true,
68+
"detect": true,
69+
"dict": true,
70+
"media": "text",
71+
"os_type": "web",
72+
"replaced": true,
73+
"request_id": "web_fanyi",
74+
"source": req.Text,
75+
"trans_type": "auto2" + req.ToLang,
76+
}
77+
reqData, _ := json.Marshal(param)
78+
body := bytes.NewReader(reqData)
79+
80+
_, data, err = sendRequest(ctx, http.MethodPost, "https://api.interpreter.caiyunai.com/v1/translator", body, func(req *http.Request) error {
81+
req.Header.Set("Content-Type", "application/json")
82+
req.Header.Set("User-Agent", UserAgent)
83+
req.Header.Set("X-Authorization", t.token)
84+
req.Header.Set("T-Authorization", jwtResponse.Jwt)
85+
return nil
86+
})
87+
if err != nil {
88+
resp.Err = fmt.Errorf("sendRequest error: %v", err)
89+
return
90+
}
91+
92+
jr := gjson.Parse(string(data))
93+
dit := jr.Get("target").String()
94+
if dit == "" {
95+
resp.Err = fmt.Errorf("cannot get translate result, resp: %s", string(data))
96+
return
97+
}
98+
99+
encoded := ""
100+
for _, s := range dit {
101+
if i := strings.IndexRune(t.seq1, s); i > -1 {
102+
encoded += string(t.seq2[i])
103+
} else {
104+
encoded += string(s)
105+
}
106+
}
107+
108+
result, err := base64.StdEncoding.DecodeString(encoded)
109+
if err != nil {
110+
resp.Err = fmt.Errorf("base64 decode error: %v", err)
111+
return
112+
}
113+
114+
resp.Result = string(result)
115+
return
116+
}
117+
118+
func (*caiyunTranslator) convertLanguage(language string) (string, error) {
119+
var l string
120+
switch language {
121+
case Chinese:
122+
l = "zh"
123+
case Japanese, English, Russian, French, Spanish:
124+
l = language
125+
}
126+
127+
if l == "" {
128+
return "", fmt.Errorf("unsupported target language: %s", language)
129+
}
130+
131+
return l, nil
132+
}

caiyun_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package fy
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestCaiyunTranslate(t *testing.T) {
11+
{
12+
resp := CaiyunTranslate(context.Background(), Request{
13+
ToLang: Chinese,
14+
Text: "One",
15+
})
16+
assert.Nil(t, resp.Err)
17+
expectedResp := newResp(caiyun)
18+
expectedResp.Result = "一个"
19+
assert.Equal(t, expectedResp, resp)
20+
}
21+
22+
{
23+
resp := CaiyunTranslate(context.Background(), Request{
24+
ToLang: English,
25+
Text: "一",
26+
})
27+
assert.Nil(t, resp.Err)
28+
expectedResp := newResp(caiyun)
29+
expectedResp.Result = "One"
30+
assert.Equal(t, expectedResp, resp)
31+
}
32+
}

deepl.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func (t *deeplTranslator) translate(ctx context.Context, req Request) (resp *Res
5252
}
5353

5454
func (*deeplTranslator) convertLanguage(language string) (string, error) {
55-
l := language
55+
var l string
5656
switch language {
5757
case Chinese:
5858
l = "ZH"
@@ -70,7 +70,7 @@ func (*deeplTranslator) convertLanguage(language string) (string, error) {
7070
l = "ES"
7171
}
7272
if l == "" {
73-
fmt.Println("unsupported target language")
73+
return "", fmt.Errorf("unsupported target language: %s", language)
7474
}
7575

7676
return l, nil

fy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const (
2020
)
2121

2222
var Translators = []translator{
23-
baidu, bing, google, sogou, tencent, youdao, deepl,
23+
baidu, bing, google, sogou, tencent, youdao, deepl, caiyun,
2424
}
2525

2626
// Request translation request

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/xwjdsh/fy
33
require (
44
github.com/atotto/clipboard v0.1.2
55
github.com/fatih/color v1.7.0
6+
github.com/google/uuid v1.3.0 // indirect
67
github.com/mattn/go-colorable v0.1.1 // indirect
78
github.com/mattn/go-isatty v0.0.7 // indirect
89
github.com/robertkrimen/otto v0.0.0-20180617131154-15f95af6e78d

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
44
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
55
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
66
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
7+
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
8+
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
79
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
810
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
911
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=

0 commit comments

Comments
 (0)