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
1ddc9ae4
You need to sign in or sign up before continuing.
Commit
1ddc9ae4
authored
Jan 16, 2025
by
mingyard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:tts 合成音频
parent
c7e4ad25
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
152 additions
and
0 deletions
+152
-0
constants.ts
src/common/utils/constants.ts
+16
-0
app.ts
src/config/app.ts
+8
-0
service.ts
src/config/service.ts
+2
-0
baseDto.ts
src/controller/translate/dto/baseDto.ts
+8
-0
textToSpeechReq.dto.ts
src/controller/translate/dto/req/textToSpeechReq.dto.ts
+37
-0
translate.controller.ts
src/controller/translate/translate.controller.ts
+59
-0
translate.service.ts
src/controller/translate/translate.service.ts
+22
-0
No files found.
src/common/utils/constants.ts
View file @
1ddc9ae4
...
@@ -169,3 +169,19 @@ export const FanYiGouTargetLanguages = {
...
@@ -169,3 +169,19 @@ export const FanYiGouTargetLanguages = {
EN
:
'en'
,
EN
:
'en'
,
ZH
:
'zh'
,
ZH
:
'zh'
,
};
};
// tts 音色列表
export
const
TTS_VOICE_LIST
=
[
{
uuid
:
'3e7a6cb0-3bae-4af9-bb7d-abc9f1c5ebe6'
,
speaker
:
'xiaoyan'
,
name
:
'小燕'
,
provider
:
9
,
},
{
uuid
:
'ea70ee2c-94eb-4a32-a77d-89452fdef367'
,
speaker
:
'xiaoyu'
,
name
:
'小宇'
,
provider
:
9
,
},
];
src/config/app.ts
View file @
1ddc9ae4
...
@@ -41,6 +41,10 @@ interface AppConfig {
...
@@ -41,6 +41,10 @@ interface AppConfig {
/** 应用私钥 */
/** 应用私钥 */
privateKey
:
string
;
privateKey
:
string
;
};
};
obs
:
{
endpoint
:
string
;
};
}
}
const
server
=
env
.
APP_SERVER
??
'http://localhost:3000'
;
const
server
=
env
.
APP_SERVER
??
'http://localhost:3000'
;
...
@@ -71,4 +75,8 @@ export const app: AppConfig = {
...
@@ -71,4 +75,8 @@ export const app: AppConfig = {
publicKey
:
env
.
APP_RSA_PUBLIC_KEY
??
''
,
publicKey
:
env
.
APP_RSA_PUBLIC_KEY
??
''
,
privateKey
:
env
.
APP_RSA_PRIVATE_KEY
??
''
,
privateKey
:
env
.
APP_RSA_PRIVATE_KEY
??
''
,
},
},
obs
:
{
endpoint
:
env
.
APP_OBS_ENDPOINT
??
'https://resources.laihua.com'
,
},
};
};
src/config/service.ts
View file @
1ddc9ae4
...
@@ -3,6 +3,7 @@ import { env } from './env';
...
@@ -3,6 +3,7 @@ import { env } from './env';
export
interface
ServiceConfig
{
export
interface
ServiceConfig
{
tts
:
{
tts
:
{
txAsrTokenUrl
:
string
;
txAsrTokenUrl
:
string
;
serviceUrl
:
string
;
};
};
fanYiGou
:
{
fanYiGou
:
{
endpoint
:
string
;
endpoint
:
string
;
...
@@ -14,6 +15,7 @@ export interface ServiceConfig {
...
@@ -14,6 +15,7 @@ export interface ServiceConfig {
export
const
service
:
ServiceConfig
=
{
export
const
service
:
ServiceConfig
=
{
tts
:
{
tts
:
{
txAsrTokenUrl
:
env
.
TTS_TX_ASR_TOKEN_URL
??
''
,
txAsrTokenUrl
:
env
.
TTS_TX_ASR_TOKEN_URL
??
''
,
serviceUrl
:
env
.
TTS_SERVICE_URL
??
''
,
},
},
fanYiGou
:
{
fanYiGou
:
{
endpoint
:
env
.
FAN_YI_GOU_ENDPOINT
??
'https://www.fanyigou.com'
,
endpoint
:
env
.
FAN_YI_GOU_ENDPOINT
??
'https://www.fanyigou.com'
,
...
...
src/controller/translate/dto/baseDto.ts
0 → 100644
View file @
1ddc9ae4
export
class
TTSDto
{
text
:
string
;
speaker
:
string
;
// 默认 elevenLabs 服务商
provider
:
number
=
9
;
// 默认语速 5
speed
?:
number
=
5
;
}
src/controller/translate/dto/req/textToSpeechReq.dto.ts
0 → 100644
View file @
1ddc9ae4
import
{
ApiProperty
}
from
'@nestjs/swagger'
;
import
{
Expose
}
from
'class-transformer'
;
import
{
IsNotEmpty
,
IsNumber
,
IsOptional
,
IsString
}
from
'class-validator'
;
export
class
TextToSpeechReqDto
{
@
ApiProperty
({
description
:
'要转换为语音的文本'
,
type
:
String
,
example
:
'要转换为语音的文本'
,
})
@
Expose
()
@
IsNotEmpty
()
@
IsString
()
text
:
string
;
@
ApiProperty
({
description
:
'语音发音人Id'
,
type
:
String
,
example
:
'uuid'
,
})
@
Expose
()
@
IsNotEmpty
()
@
IsString
()
speaker
:
string
;
@
ApiProperty
({
description
:
'语音速度'
,
type
:
Number
,
required
:
false
,
default
:
5
,
example
:
5
,
})
@
Expose
()
@
IsOptional
()
@
IsNumber
()
speed
?:
number
=
5
;
}
src/controller/translate/translate.controller.ts
View file @
1ddc9ae4
...
@@ -18,6 +18,10 @@ import { TranslateImageReqDto } from './dto/req/translateImageReq.dto';
...
@@ -18,6 +18,10 @@ import { TranslateImageReqDto } from './dto/req/translateImageReq.dto';
import
{
TranslateProgressReqDto
}
from
'./dto/req/translateProgressReq.dto'
;
import
{
TranslateProgressReqDto
}
from
'./dto/req/translateProgressReq.dto'
;
import
{
ApiResponseInterceptor
}
from
'@/common/interceptor/api.response.interceptor'
;
import
{
ApiResponseInterceptor
}
from
'@/common/interceptor/api.response.interceptor'
;
import
{
Response
}
from
'express'
;
import
{
Response
}
from
'express'
;
import
{
TextToSpeechReqDto
}
from
'./dto/req/textToSpeechReq.dto'
;
import
{
TTS_VOICE_LIST
}
from
'@/common/utils/constants'
;
import
{
BadRequestError
}
from
'@/common/exception/badRequest/BadRequestError'
;
import
{
config
}
from
'@/config'
;
@
ApiTags
(
'translate'
)
@
ApiTags
(
'translate'
)
@
UseInterceptors
(
ApiResponseInterceptor
)
@
UseInterceptors
(
ApiResponseInterceptor
)
...
@@ -162,4 +166,59 @@ export class TranslateController {
...
@@ -162,4 +166,59 @@ export class TranslateController {
):
Promise
<
any
>
{
):
Promise
<
any
>
{
return
await
this
.
translateService
.
downloadImage
(
dto
.
taskId
,
res
);
return
await
this
.
translateService
.
downloadImage
(
dto
.
taskId
,
res
);
}
}
// text合成语音
@
Post
(
'textToSpeech'
)
@
ApiOperation
({
summary
:
'text合成语音'
})
@
ApiResponse
({
status
:
200
,
description
:
'成功返回合成语音文件'
,
example
:
{
code
:
200
,
message
:
'success'
,
data
:
{
url
:
'http://xxx.com/xxx.mp3'
,
},
},
})
@
Auth
()
async
textToSpeech
(@
Body
()
dto
:
TextToSpeechReqDto
):
Promise
<
any
>
{
const
voice
=
TTS_VOICE_LIST
.
find
((
item
)
=>
item
.
uuid
===
dto
.
speaker
);
if
(
!
voice
)
{
throw
BadRequestError
.
default
(
'音色不存在'
);
}
const
result
=
await
this
.
translateService
.
tts
({
...
dto
,
speaker
:
voice
.
speaker
,
provider
:
voice
.
provider
,
});
return
`
${
config
.
obs
.
endpoint
}
/
${
result
.
filename
}
`
;
}
// 获取语音合成支持的语音列表
@
Get
(
'voiceList'
)
@
ApiOperation
({
summary
:
'获取语音合成支持的语音列表'
})
@
ApiResponse
({
status
:
200
,
description
:
'成功返回支持的语音列表'
,
example
:
{
code
:
200
,
message
:
'success'
,
data
:
[
{
uuid
:
'3e7a6cb0-3bae-4af9-bb7d-abc9f1c5ebe6'
,
speaker
:
'xiaoyan'
,
name
:
'小燕'
,
provider
:
9
,
},
],
},
})
@
Auth
()
async
getVoiceList
():
Promise
<
any
>
{
return
TTS_VOICE_LIST
;
}
}
}
src/controller/translate/translate.service.ts
View file @
1ddc9ae4
...
@@ -13,6 +13,7 @@ import * as FormData from 'form-data';
...
@@ -13,6 +13,7 @@ import * as FormData from 'form-data';
import
{
TranslateImageReqDto
}
from
'./dto/req/translateImageReq.dto'
;
import
{
TranslateImageReqDto
}
from
'./dto/req/translateImageReq.dto'
;
import
{
Response
}
from
'express'
;
import
{
Response
}
from
'express'
;
import
axios
,
{
AxiosResponse
}
from
'axios'
;
import
axios
,
{
AxiosResponse
}
from
'axios'
;
import
{
TTSDto
}
from
'./dto/baseDto'
;
@
Injectable
()
@
Injectable
()
export
class
TranslateService
{
export
class
TranslateService
{
...
@@ -206,4 +207,25 @@ export class TranslateService {
...
@@ -206,4 +207,25 @@ export class TranslateService {
// 将文件流返回给前端
// 将文件流返回给前端
response
.
data
.
pipe
(
res
);
response
.
data
.
pipe
(
res
);
}
}
// tts 语音合成
async
tts
(
dto
:
TTSDto
):
Promise
<
any
>
{
const
result
=
await
axiosPostRequest
(
config
.
service
.
tts
.
serviceUrl
,
{
...
dto
,
},
{
headers
:
{
'Content-Type'
:
'application/json'
,
},
},
);
if
(
!
result
?.
data
||
result
?.
data
?.
filename
)
{
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