Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
T
translation-server
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
qinmingyuan
translation-server
Commits
1324bcb1
You need to sign in or sign up before continuing.
Commit
1324bcb1
authored
Jan 15, 2025
by
mingyard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:翻译狗相关接口
parent
133fdb1d
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
383 additions
and
9 deletions
+383
-9
launch.json
.vscode/launch.json
+16
-0
constants.ts
src/common/utils/constants.ts
+68
-0
service.ts
src/config/service.ts
+2
-0
translateImageReq.dto.ts
src/controller/translate/dto/req/translateImageReq.dto.ts
+29
-0
translateProgressReq.dto.ts
src/controller/translate/dto/req/translateProgressReq.dto.ts
+15
-0
translate.controller.ts
src/controller/translate/translate.controller.ts
+120
-5
translate.service.ts
src/controller/translate/translate.service.ts
+133
-4
No files found.
.vscode/launch.json
0 → 100644
View file @
1324bcb1
{
//
使用
IntelliSense
了解相关属性。
//
悬停以查看现有属性的描述。
//
欲了解更多信息,请访问
:
https
:
//go.microsoft.com/fwlink/?linkid=
830387
"version"
:
"0.2.0"
,
"configurations"
:
[
{
"type"
:
"node-terminal"
,
"name"
:
"运行脚本: start"
,
"request"
:
"launch"
,
"command"
:
"yarn run start"
,
"cwd"
:
"${workspaceFolder}"
}
]
}
\ No newline at end of file
src/common/utils/constants.ts
View file @
1324bcb1
...
@@ -101,3 +101,71 @@ export enum SupportLanguages {
...
@@ -101,3 +101,71 @@ export enum SupportLanguages {
UK
=
'UK'
,
UK
=
'UK'
,
ZH
=
'ZH'
,
ZH
=
'ZH'
,
}
}
// 翻译狗支持的语言
export
const
FAN_YI_GOU_SOURCE_LANGUAGES
=
[
{
key
:
'pl'
,
language
:
'Polish'
,
name
:
'波兰'
},
{
key
:
'dan'
,
language
:
'Danish'
,
name
:
'丹麦语'
},
{
key
:
'de'
,
language
:
'German'
,
name
:
'德语'
},
{
key
:
'ru'
,
language
:
'Russian'
,
name
:
'俄语'
},
{
key
:
'fra'
,
language
:
'French'
,
name
:
'法语'
},
{
key
:
'kor'
,
language
:
'Korean'
,
name
:
'韩语'
},
{
key
:
'nl'
,
language
:
'Dutch'
,
name
:
'荷兰语'
},
{
key
:
'rom'
,
language
:
'Romanian'
,
name
:
'罗马尼亚语'
},
{
key
:
'ms'
,
language
:
'Malay'
,
name
:
'马来语'
},
{
key
:
'pt'
,
language
:
'Portuguese'
,
name
:
'葡萄牙语'
},
{
key
:
'jp'
,
language
:
'Japanese'
,
name
:
'日语'
},
{
key
:
'swe'
,
language
:
'Swedish'
,
name
:
'瑞典语'
},
{
key
:
'tr'
,
language
:
'Turkish'
,
name
:
'土耳其语'
},
{
key
:
'spa'
,
language
:
'Spanish'
,
name
:
'西班牙语'
},
{
key
:
'el'
,
language
:
'Greek'
,
name
:
'希腊语'
},
{
key
:
'hu'
,
language
:
'Hungarian'
,
name
:
'匈牙利语'
},
{
key
:
'it'
,
language
:
'Italian'
,
name
:
'意大利语'
},
{
key
:
'id'
,
language
:
'Indonesian'
,
name
:
'印尼语'
},
{
key
:
'en'
,
language
:
'English'
,
name
:
'英语'
},
{
key
:
'zh'
,
language
:
'Chinese'
,
name
:
'中文'
},
];
// 翻译狗支持的目标语言
export
const
FAN_YI_GOU_TARGET_LANGUAGES
=
[
{
key
:
'kor'
,
language
:
'Korean'
,
name
:
'韩语'
},
{
key
:
'jp'
,
language
:
'Japanese'
,
name
:
'日语'
},
{
key
:
'th'
,
language
:
'Thai'
,
name
:
'泰语'
},
{
key
:
'el'
,
language
:
'Greek'
,
name
:
'希腊语'
},
{
key
:
'en'
,
language
:
'English'
,
name
:
'英语'
},
{
key
:
'zh'
,
language
:
'Chinese'
,
name
:
'中文'
},
];
// 翻译狗支持的语言
export
const
FanYiGouSourceLanguages
=
{
PL
:
'pl'
,
DAN
:
'dan'
,
DE
:
'de'
,
RU
:
'ru'
,
FRA
:
'fra'
,
KOR
:
'kor'
,
NL
:
'nl'
,
ROM
:
'rom'
,
MS
:
'ms'
,
PT
:
'pt'
,
JP
:
'jp'
,
SWE
:
'swe'
,
TR
:
'tr'
,
SPA
:
'spa'
,
EL
:
'el'
,
HU
:
'hu'
,
IT
:
'it'
,
ID
:
'id'
,
EN
:
'en'
,
ZH
:
'zh'
,
};
// 翻译狗支持的目标语言
export
const
FanYiGouTargetLanguages
=
{
KOR
:
'kor'
,
JP
:
'jp'
,
TH
:
'th'
,
EL
:
'el'
,
EN
:
'en'
,
ZH
:
'zh'
,
};
src/config/service.ts
View file @
1324bcb1
...
@@ -7,6 +7,7 @@ export interface ServiceConfig {
...
@@ -7,6 +7,7 @@ export interface ServiceConfig {
fanYiGou
:
{
fanYiGou
:
{
endpoint
:
string
;
endpoint
:
string
;
secret
:
string
;
secret
:
string
;
appId
:
string
;
};
};
}
}
...
@@ -17,5 +18,6 @@ export const service: ServiceConfig = {
...
@@ -17,5 +18,6 @@ export const service: ServiceConfig = {
fanYiGou
:
{
fanYiGou
:
{
endpoint
:
env
.
FAN_YI_GOU_ENDPOINT
??
'https://www.fanyigou.com'
,
endpoint
:
env
.
FAN_YI_GOU_ENDPOINT
??
'https://www.fanyigou.com'
,
secret
:
env
.
FAN_YI_GOU_SECRET
??
''
,
secret
:
env
.
FAN_YI_GOU_SECRET
??
''
,
appId
:
env
.
FAN_YI_GOU_APP_ID
??
''
,
},
},
};
};
src/controller/translate/dto/req/translateImageReq.dto.ts
0 → 100644
View file @
1324bcb1
import
{
FanYiGouSourceLanguages
,
FanYiGouTargetLanguages
,
}
from
'@/common/utils/constants'
;
import
{
ApiProperty
}
from
'@nestjs/swagger'
;
import
{
Expose
}
from
'class-transformer'
;
import
{
IsEnum
,
IsNotEmpty
}
from
'class-validator'
;
export
class
TranslateImageReqDto
{
@
ApiProperty
({
description
:
'目标语言'
,
enum
:
FanYiGouTargetLanguages
,
example
:
FanYiGouTargetLanguages
.
EN
,
})
@
Expose
()
@
IsNotEmpty
()
@
IsEnum
(
FanYiGouTargetLanguages
)
target
:
string
;
@
ApiProperty
({
description
:
'源语言'
,
enum
:
FanYiGouSourceLanguages
,
example
:
FanYiGouSourceLanguages
.
ZH
,
})
@
Expose
()
@
IsNotEmpty
()
@
IsEnum
(
FanYiGouSourceLanguages
)
source
:
string
;
}
src/controller/translate/dto/req/translateProgressReq.dto.ts
0 → 100644
View file @
1324bcb1
import
{
ApiProperty
}
from
'@nestjs/swagger'
;
import
{
Expose
}
from
'class-transformer'
;
import
{
IsNotEmpty
,
IsString
}
from
'class-validator'
;
export
class
TranslateProgressReqDto
{
@
ApiProperty
({
description
:
'任务ID'
,
type
:
String
,
example
:
123456
,
})
@
Expose
()
@
IsNotEmpty
()
@
IsString
()
taskId
:
string
;
}
src/controller/translate/translate.controller.ts
View file @
1324bcb1
import
{
Body
,
Controller
,
Get
,
Post
}
from
'@nestjs/common'
;
import
{
Body
,
Controller
,
Get
,
Post
,
Query
,
UploadedFile
,
UseInterceptors
,
}
from
'@nestjs/common'
;
import
{
TranslateService
}
from
'./translate.service'
;
import
{
TranslateService
}
from
'./translate.service'
;
import
{
Auth
}
from
'@/common/decorators/auth.decorator'
;
import
{
Auth
}
from
'@/common/decorators/auth.decorator'
;
import
{
ApiTags
,
ApiOperation
,
ApiResponse
}
from
'@nestjs/swagger'
;
import
{
ApiTags
,
ApiOperation
,
ApiResponse
}
from
'@nestjs/swagger'
;
import
{
TranslateReqDto
}
from
'./dto/req/translateReq.dto'
;
import
{
TranslateReqDto
}
from
'./dto/req/translateReq.dto'
;
import
{
TranslateResDto
}
from
'./dto/res/translateRes.dto'
;
import
{
TranslateResDto
}
from
'./dto/res/translateRes.dto'
;
import
{
FileInterceptor
}
from
'@nestjs/platform-express'
;
import
{
TranslateImageReqDto
}
from
'./dto/req/translateImageReq.dto'
;
import
{
TranslateProgressReqDto
}
from
'./dto/req/translateProgressReq.dto'
;
import
{
ApiResponseInterceptor
}
from
'@/common/interceptor/api.response.interceptor'
;
@
ApiTags
(
'translate'
)
@
ApiTags
(
'translate'
)
@
UseInterceptors
(
ApiResponseInterceptor
)
@
Controller
(
'translate'
)
@
Controller
(
'translate'
)
export
class
TranslateController
{
export
class
TranslateController
{
constructor
(
private
readonly
translateService
:
TranslateService
)
{}
constructor
(
private
readonly
translateService
:
TranslateService
)
{}
...
@@ -17,9 +30,13 @@ export class TranslateController {
...
@@ -17,9 +30,13 @@ export class TranslateController {
status
:
200
,
status
:
200
,
description
:
'成功返回支持的语言列表'
,
description
:
'成功返回支持的语言列表'
,
example
:
{
example
:
{
code
:
200
,
message
:
'success'
,
data
:
{
source
:
[{
key
:
'AR'
,
language
:
'Arabic'
,
name
:
'阿拉伯语'
}],
source
:
[{
key
:
'AR'
,
language
:
'Arabic'
,
name
:
'阿拉伯语'
}],
target
:
[{
key
:
'AR'
,
language
:
'Arabic'
,
name
:
'阿拉伯语'
}],
target
:
[{
key
:
'AR'
,
language
:
'Arabic'
,
name
:
'阿拉伯语'
}],
},
},
},
})
})
@
Auth
()
@
Auth
()
async
getLanguages
():
Promise
<
{
source
:
object
[];
target
:
object
[]
}
>
{
async
getLanguages
():
Promise
<
{
source
:
object
[];
target
:
object
[]
}
>
{
...
@@ -33,8 +50,12 @@ export class TranslateController {
...
@@ -33,8 +50,12 @@ export class TranslateController {
status
:
200
,
status
:
200
,
description
:
'成功返回翻译结果'
,
description
:
'成功返回翻译结果'
,
example
:
{
example
:
{
source
:
'EN'
,
code
:
200
,
text
:
'要翻译的文本'
,
message
:
'success'
,
data
:
{
source
:
'ZH'
,
text
:
'weekly'
,
},
},
},
})
})
@
Auth
()
@
Auth
()
...
@@ -43,4 +64,98 @@ export class TranslateController {
...
@@ -43,4 +64,98 @@ export class TranslateController {
):
Promise
<
TranslateResDto
>
{
):
Promise
<
TranslateResDto
>
{
return
await
this
.
translateService
.
translateText
(
translateDto
);
return
await
this
.
translateService
.
translateText
(
translateDto
);
}
}
// 翻译图片支持的语言
@
Get
(
'image/languages'
)
@
ApiOperation
({
summary
:
'获取翻译图片支持的语言'
})
@
ApiResponse
({
status
:
200
,
description
:
'成功返回支持的语言列表'
,
example
:
{
code
:
200
,
message
:
'success'
,
data
:
{
source
:
[{
key
:
'en'
,
language
:
'English'
,
name
:
'英语'
}],
target
:
[{
key
:
'zh'
,
language
:
'Chinese'
,
name
:
'中文'
}],
},
},
})
@
Auth
()
async
getImageLanguages
():
Promise
<
{
source
:
object
[];
target
:
object
[];
}
>
{
return
await
this
.
translateService
.
getFanYiGouLanguages
();
}
// 翻译图片
@
Post
(
'image'
)
@
ApiOperation
({
summary
:
'翻译图片'
})
@
ApiResponse
({
status
:
200
,
description
:
'成功返回翻译结果'
,
example
:
{
code
:
200
,
message
:
'success'
,
data
:
{
taskId
:
709394
,
},
},
})
@
Auth
()
@
UseInterceptors
(
FileInterceptor
(
'file'
,
{
limits
:
{
fileSize
:
4
*
1024
*
1024
},
}),
)
async
translateImage
(
@
UploadedFile
()
file
,
@
Body
()
dto
:
TranslateImageReqDto
,
):
Promise
<
any
>
{
return
await
this
.
translateService
.
translateImage
(
file
,
dto
);
}
// 获取翻译进度
@
Get
(
'progress'
)
@
ApiOperation
({
summary
:
'获取翻译进度'
})
@
ApiResponse
({
status
:
200
,
description
:
'成功返回翻译进度'
,
example
:
{
code
:
200
,
message
:
'success'
,
data
:
{
tid
:
709412
,
createTime
:
'2025-01-15 16:54:08'
,
updateTime
:
''
,
status
:
1
,
title
:
'20250111-165032'
,
pageCount
:
1
,
percent
:
'0.00'
,
fromLan
:
'英语'
,
detectLan
:
''
,
toLan
:
'中文'
,
docType
:
'jpeg'
,
msg
:
'进行中'
,
originalCharCount
:
0
,
},
},
})
@
Auth
()
async
getProgress
(@
Query
()
dto
:
TranslateProgressReqDto
):
Promise
<
any
>
{
return
await
this
.
translateService
.
getProgress
(
dto
.
taskId
);
}
// 获取翻译结果
@
Get
(
'result'
)
@
ApiOperation
({
summary
:
'获取翻译结果'
})
@
ApiResponse
({
status
:
200
,
description
:
'成功返回翻译结果'
,
example
:
{},
})
@
Auth
()
async
getResult
(@
Query
()
dto
:
TranslateProgressReqDto
):
Promise
<
any
>
{
return
await
this
.
translateService
.
downloadImage
(
dto
.
taskId
);
}
}
}
src/controller/translate/translate.service.ts
View file @
1324bcb1
...
@@ -8,7 +8,9 @@ import { TranslateResDto } from './dto/res/translateRes.dto';
...
@@ -8,7 +8,9 @@ import { TranslateResDto } from './dto/res/translateRes.dto';
import
{
axiosPostRequest
}
from
'@/common/utils/requests/request'
;
import
{
axiosPostRequest
}
from
'@/common/utils/requests/request'
;
import
{
config
}
from
'@/config'
;
import
{
config
}
from
'@/config'
;
import
{
BadRequestError
}
from
'@/common/exception/badRequest/BadRequestError'
;
import
{
BadRequestError
}
from
'@/common/exception/badRequest/BadRequestError'
;
import
crypto
from
'crypto'
;
import
*
as
crypto
from
'crypto'
;
import
*
as
FormData
from
'form-data'
;
import
{
TranslateImageReqDto
}
from
'./dto/req/translateImageReq.dto'
;
@
Injectable
()
@
Injectable
()
export
class
TranslateService
{
export
class
TranslateService
{
...
@@ -22,6 +24,17 @@ export class TranslateService {
...
@@ -22,6 +24,17 @@ export class TranslateService {
};
};
}
}
// 获取翻译狗支持的语言
async
getFanYiGouLanguages
():
Promise
<
{
source
:
object
[];
target
:
object
[];
}
>
{
return
{
source
:
DEEPL_SOURCE_LANGUAGES
,
target
:
DEEPL_TARGET_LANGUAGES
,
};
}
// 翻译文本
// 翻译文本
async
translateText
(
translateDto
:
TranslateReqDto
):
Promise
<
TranslateResDto
>
{
async
translateText
(
translateDto
:
TranslateReqDto
):
Promise
<
TranslateResDto
>
{
console
.
log
(
'config.deepl'
,
config
.
deepl
);
console
.
log
(
'config.deepl'
,
config
.
deepl
);
...
@@ -52,21 +65,137 @@ export class TranslateService {
...
@@ -52,21 +65,137 @@ export class TranslateService {
}
}
// 获取翻译狗token
// 获取翻译狗token
async
generateToken
(
params
,
privateKey
)
{
generateToken
(
params
)
{
params
=
{
...
params
,
appid
:
config
.
service
.
fanYiGou
.
appId
,
privatekey
:
config
.
service
.
fanYiGou
.
secret
,
};
// 按照key=value的格式,并按照参数名ASCII字典序排序
// 按照key=value的格式,并按照参数名ASCII字典序排序
const
sortedParams
=
Object
.
keys
(
params
)
const
sortedParams
=
Object
.
keys
(
params
)
.
sort
()
.
sort
()
.
map
((
key
)
=>
`
${
key
}
=
${
params
[
key
]}
`
)
.
map
((
key
)
=>
`
${
key
}
=
${
params
[
key
]}
`
)
.
join
(
'&'
);
.
join
(
'&'
);
const
stringToHash
=
`
${
sortedParams
}
&privatekey=
${
privateKey
}
`
;
// 生成MD5哈希并转换为大写
// 生成MD5哈希并转换为大写
const
token
=
crypto
const
token
=
crypto
.
createHash
(
'md5'
)
.
createHash
(
'md5'
)
.
update
(
s
tringToHash
)
.
update
(
s
ortedParams
)
.
digest
(
'hex'
)
.
digest
(
'hex'
)
.
toUpperCase
();
.
toUpperCase
();
return
token
;
return
token
;
}
}
getFileMD5
(
fileBuffer
:
Buffer
):
string
{
return
crypto
.
createHash
(
'md5'
).
update
(
fileBuffer
).
digest
(
'hex'
);
}
async
translateImage
(
file
,
dto
:
TranslateImageReqDto
):
Promise
<
any
>
{
const
params
=
{
nonce_str
:
crypto
.
randomUUID
(),
from
:
dto
.
source
,
to
:
dto
.
target
,
md5
:
this
.
getFileMD5
(
file
.
buffer
),
};
const
token
=
this
.
generateToken
(
params
);
// 构建 FormData 数据
const
formData
=
new
FormData
();
formData
.
append
(
'file'
,
file
.
buffer
,
{
filename
:
file
.
originalname
,
contentType
:
file
.
mimetype
,
});
formData
.
append
(
'appid'
,
config
.
service
.
fanYiGou
.
appId
);
formData
.
append
(
'md5'
,
params
.
md5
);
formData
.
append
(
'nonce_str'
,
params
.
nonce_str
);
formData
.
append
(
'from'
,
params
.
from
);
formData
.
append
(
'to'
,
params
.
to
);
formData
.
append
(
'token'
,
token
);
const
result
=
await
axiosPostRequest
(
`
${
config
.
service
.
fanYiGou
.
endpoint
}
/TranslateApi/api/image/uploadTranslateImage`
,
formData
,
{
headers
:
{
...
formData
.
getHeaders
(),
},
},
);
if
(
!
result
?.
data
)
{
throw
BadRequestError
.
default
(
'翻译失败'
);
}
return
result
?.
data
?.
data
;
}
// 获取翻译进度
async
getProgress
(
taskId
:
string
):
Promise
<
any
>
{
const
params
=
{
nonce_str
:
crypto
.
randomUUID
(),
tid
:
taskId
,
};
const
token
=
this
.
generateToken
(
params
);
// 构建 FormData 数据
const
formData
=
new
FormData
();
formData
.
append
(
'appid'
,
config
.
service
.
fanYiGou
.
appId
);
formData
.
append
(
'nonce_str'
,
params
.
nonce_str
);
formData
.
append
(
'tid'
,
params
.
tid
);
formData
.
append
(
'token'
,
token
);
const
result
=
await
axiosPostRequest
(
`
${
config
.
service
.
fanYiGou
.
endpoint
}
/TranslateApi/api/image/queryImageTransProgress`
,
formData
,
{
headers
:
{
...
formData
.
getHeaders
(),
},
},
);
if
(
!
result
?.
data
)
{
throw
BadRequestError
.
default
(
'获取翻译进度失败'
);
}
return
result
?.
data
.
data
;
}
// 下载翻译图片
async
downloadImage
(
taskId
:
string
):
Promise
<
any
>
{
const
params
=
{
nonce_str
:
crypto
.
randomUUID
(),
tid
:
taskId
,
};
const
token
=
this
.
generateToken
(
params
);
// 构建 FormData 数据
const
formData
=
new
FormData
();
formData
.
append
(
'appid'
,
config
.
service
.
fanYiGou
.
appId
);
formData
.
append
(
'nonce_str'
,
params
.
nonce_str
);
formData
.
append
(
'tid'
,
params
.
tid
);
formData
.
append
(
'token'
,
token
);
const
result
=
await
axiosPostRequest
(
`
${
config
.
service
.
fanYiGou
.
endpoint
}
/TranslateApi/api/image/downloadImage`
,
formData
,
{
headers
:
{
...
formData
.
getHeaders
(),
},
},
);
if
(
!
result
?.
data
)
{
throw
BadRequestError
.
default
(
'下载翻译图片失败'
);
}
return
result
?.
data
;
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment