Skip to content

Commit

Permalink
feat(#13): 新增百度智能云翻译翻译;
Browse files Browse the repository at this point in the history
  • Loading branch information
speauty committed Mar 12, 2024
1 parent 164d6f0 commit 5ae43ab
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 3 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
tidy:
go mod tidy

BinName=anto-v3.6.0-windows.exe
BinName=anto-v3.6.2-windows.exe

deploy: rs build

Expand Down
4 changes: 3 additions & 1 deletion bootstrap/boot.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"anto/cfg"
"anto/common"
"anto/domain/repository"
"anto/domain/service/translator/ai_baidu"
"anto/domain/service/translator/ali_cloud_mt"
"anto/domain/service/translator/baidu"
"anto/domain/service/translator/caiyunai"
Expand Down Expand Up @@ -49,13 +50,14 @@ func Boot(_ context.Context) {
openai_sweet.API().Init(cfg.Singleton().OpenAISweet)
deepl.API().Init(cfg.Singleton().DeepL)
deepl_pro.API().Init(cfg.Singleton().DeepLPro)
ai_baidu.API().Init(cfg.Singleton().AiBaidu)

repository.GetTranslators().Register(
huawei_cloud_nlp.API(), baidu.API(),
tencent_cloud_mt.API(), openapi_youdao.API(),
ali_cloud_mt.API(), caiyunai.API(), niutrans.API(),
volcengine.API(), g_deepl_x.API(),
google_cloud.API(), openai.API(), deepl.API(), deepl_pro.API(),
openai_sweet.API(),
openai_sweet.API(), ai_baidu.API(),
)
}
3 changes: 3 additions & 0 deletions cfg/cfg.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cfg

import (
"anto/domain/service/translator/ai_baidu"
"anto/domain/service/translator/ali_cloud_mt"
"anto/domain/service/translator/baidu"
"anto/domain/service/translator/caiyunai"
Expand Down Expand Up @@ -48,6 +49,7 @@ func Singleton() *Cfg {
apiSingleton.OpenAISweet = new(openai_sweet.Config).Default().(*openai_sweet.Config)
apiSingleton.DeepL = new(deepl.Config).Default().(*deepl.Config)
apiSingleton.DeepLPro = new(deepl_pro.Config).Default().(*deepl_pro.Config)
apiSingleton.AiBaidu = new(ai_baidu.Config).Default().(*ai_baidu.Config)
})
return apiSingleton
}
Expand All @@ -71,6 +73,7 @@ type Cfg struct {
OpenAISweet *openai_sweet.Config `mapstructure:"openai_sweet"`
DeepL *deepl.Config `mapstructure:"deepl"`
DeepLPro *deepl_pro.Config `mapstructure:"deepl_pro"`
AiBaidu *ai_baidu.Config `mapstructure:"ai_baidu"`

currentViper *viper.Viper `mapstructure:"-"`
}
Expand Down
1 change: 1 addition & 0 deletions cfg/opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func (customC *Cfg) InitConfig() error {
_ = customC.Niutrans.SyncDisk(currentViper)
_ = customC.VolcEngine.SyncDisk(currentViper)
_ = customC.YouDao.SyncDisk(currentViper)
_ = customC.AiBaidu.SyncDisk(currentViper)

return customC.Sync()
}
Expand Down
2 changes: 1 addition & 1 deletion common/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package common
const (
AppName = "anto"
Author = "speauty"
Version = "v3.6.0"
Version = "v3.6.2"
DownloadLatestVersionUrl = "http://kodo.app.speauty.cn/anto-latest-windows.exe"

GoUidLen = 8
Expand Down
118 changes: 118 additions & 0 deletions domain/service/translator/ai_baidu/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package ai_baidu

import (
"anto/domain/service/translator"
"encoding/json"
"fmt"
"github.com/imroc/req/v3"
"github.com/spf13/viper"
"io"
"time"
)

type Config struct {
*translator.DefaultConfig
ApiKey string `mapstructure:"api_key"` // 应用关键字
SecretKey string `mapstructure:"secret_key"` // 应用密钥
QPS int `mapstructure:"qps"`
MaxCharNum int `mapstructure:"max_single_text_length"`
MaxCoroutineNum int `mapstructure:"max_coroutine_num"`
AccessToken string `mapstructure:"access_token"`
ExpiredAt int64 `mapstructure:"expired_at"`
}

func (config *Config) Default() translator.ImplConfig {
return &Config{
ApiKey: "", SecretKey: "",
MaxCharNum: 6000, QPS: 10, MaxCoroutineNum: 5,
}
}

func (config *Config) SyncDisk(currentViper *viper.Viper) error {
tagAndVal := config.JoinAllTagAndValue(API(), config, "mapstructure")

for tag, val := range tagAndVal {
currentViper.Set(tag, val)
}
return nil
}

func (config *Config) GetAK() string { return config.ApiKey }
func (config *Config) GetSK() string { return config.SecretKey }

func (config *Config) GetQPS() int { return config.QPS }
func (config *Config) GetMaxCharNum() int { return config.MaxCharNum }
func (config *Config) GetMaxCoroutineNum() int { return config.MaxCoroutineNum }

func (config *Config) SetAK(str string) error {
if err := config.ValidatorStr(str); err != nil {
return err
}
config.ApiKey = str
return nil
}
func (config *Config) SetSK(str string) error {
if err := config.ValidatorStr(str); err != nil {
return err
}
config.SecretKey = str
return nil
}

func (config *Config) SetQPS(num int) error {
if err := config.ValidatorNum(num); err != nil {
return err
}
config.QPS = num
return nil
}

func (config *Config) SetMaxCharNum(num int) error {
if err := config.ValidatorNum(num); err != nil {
return err
}
config.MaxCharNum = num
return nil
}

func (config *Config) SetMaxCoroutineNum(num int) error {
if err := config.ValidatorNum(num); err != nil {
return err
}
config.MaxCoroutineNum = num
return nil
}

func (config *Config) GetAccessToken() (string, error) {
if config.AccessToken == "" || config.ExpiredAt < (time.Now().Unix()-3600) {
tmpUrl := fmt.Sprintf(
"https://aip.baidubce.com/oauth/2.0/token?client_id=%s&client_secret=%s&grant_type=client_credentials",
config.GetAK(), config.GetSK(),
)
resp, err := req.R().Post(tmpUrl)
if err != nil {
return "", err
}
respBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("读取报文异常, 错误: %s", err.Error())
}
auth := &authResp{}
if err = json.Unmarshal(respBytes, auth); err != nil {
return "", fmt.Errorf("解析报文异常, 错误: %s", err.Error())
}
config.AccessToken = auth.AccessToken
config.ExpiredAt = time.Now().Unix() + auth.ExpiresIn
}

return config.AccessToken, nil
}

type authResp struct {
RefreshToken string `json:"refresh_token"`
ExpiresIn int64 `json:"expires_in"`
SessionKey string `json:"session_key"`
AccessToken string `json:"access_token"`
Scope string `json:"scope"`
SessionSecret string `json:"session_secret"`
}
33 changes: 33 additions & 0 deletions domain/service/translator/ai_baidu/lang.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package ai_baidu

import (
"anto/domain/service/translator"
)

var langSupported = []translator.LangPair{
{"zh", "中文"},
{"en", "英语"},
{"jp", "日语"},
{"kor", "韩语"},
{"fra", "法语"},
{"spa", "西班牙语"},
{"th", "泰语"},
{"ara", "阿拉伯语"},
{"ru", "俄语"},
{"pt", "葡萄牙语"},
{"de", "德语"},
{"it", "意大利语"},
{"el", "希腊语"},
{"nl", "荷兰语"},
{"pl", "波兰语"},
{"bul", "保加利亚语"},
{"est", "爱沙尼亚语"},
{"dan", "丹麦语"},
{"fin", "芬兰语"},
{"cs", "捷克语"},
{"rom", "罗马尼亚语"},
{"slo", "斯洛文尼亚语"},
{"swe", "瑞典语"},
{"hu", "匈牙利语"},
{"vie", "越南语"},
}
105 changes: 105 additions & 0 deletions domain/service/translator/ai_baidu/translator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package ai_baidu

import (
"anto/domain/service/translator"
"anto/lib/log"
"context"
"encoding/json"
"fmt"
"github.com/golang-module/carbon"
"sync"
)

var api = "https://aip.baidubce.com/rpc/2.0/mt/texttrans/v1"

var (
apiTranslator *Translator
onceTranslator sync.Once
)

func API() *Translator {
onceTranslator.Do(func() {
apiTranslator = New()
})
return apiTranslator
}

func New() *Translator {
return &Translator{
id: "ai_baidu",
name: "百度智能云",
sep: "\n",
langSupported: langSupported,
}
}

type Translator struct {
id string
name string
cfg translator.ImplConfig
qps int
procMax int
textMaxLen int
langSupported []translator.LangPair
sep string
}

func (customT *Translator) Init(cfg translator.ImplConfig) { customT.cfg = cfg }

func (customT *Translator) GetId() string { return customT.id }
func (customT *Translator) GetShortId() string { return "ai_bd" }
func (customT *Translator) GetName() string { return customT.name }
func (customT *Translator) GetCfg() translator.ImplConfig { return customT.cfg }
func (customT *Translator) GetLangSupported() []translator.LangPair { return customT.langSupported }
func (customT *Translator) GetSep() string { return customT.sep }
func (customT *Translator) IsValid() bool {
return customT.cfg != nil && customT.cfg.GetAK() != "" && customT.cfg.GetSK() != ""
}

func (customT *Translator) Translate(ctx context.Context, args *translator.TranslateArgs) (*translator.TranslateRes, error) {
timeStart := carbon.Now()
accessToken, err := customT.GetCfg().(*Config).GetAccessToken()
if err != nil {
return nil, err
}
urlQueried := fmt.Sprintf("%s?access_token=%s", api, accessToken)
bodyContent := translateReq{Q: args.TextContent, From: args.FromLang, To: args.ToLang}
respBytes, err := translator.RequestSimpleHttp(ctx, customT, urlQueried, true, bodyContent, nil)
if err != nil {
return nil, err
}
respObj := new(translateResp)
if err = json.Unmarshal(respBytes, respObj); err != nil {
log.Singleton().ErrorF("解析报文异常, 引擎: %s, 错误: %s", customT.GetName(), err)
return nil, fmt.Errorf("解析报文出现异常, 错误: %s", err.Error())
}

ret := new(translator.TranslateRes)
for _, transBlockArray := range respObj.Result.TransResult {
ret.Results = append(ret.Results, &translator.TranslateResBlock{
Id: transBlockArray.Src,
TextTranslated: transBlockArray.Dst,
})
}

ret.TimeUsed = int(carbon.Now().DiffInSeconds(timeStart))
return ret, nil
}

type translateReq struct {
Q string `json:"q"`
From string `json:"from"`
To string `json:"to"`
}

type translateResp struct {
Result struct {
From string `json:"from"`
TransResult []struct {
Dst string `json:"dst"`
Src string `json:"src"`
} `json:"trans_result"`
To string `json:"to"`
} `json:"result"`
LogId int64 `json:"log_id"`
}

0 comments on commit 5ae43ab

Please sign in to comment.