|
|
package common
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
"context"
|
|
|
"encoding/json"
|
|
|
"fmt"
|
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
|
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
|
|
nls "github.com/aliyun/alibabacloud-nls-go-sdk"
|
|
|
"github.com/google/uuid"
|
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
|
"gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/svc"
|
|
|
"gitlab.fjmaimaimai.com/allied-creation/sumifcc/cmd/bsi/api/internal/types"
|
|
|
"gitlab.fjmaimaimai.com/allied-creation/sumifcc/pkg/xerr"
|
|
|
"io/ioutil"
|
|
|
"net/http"
|
|
|
"os"
|
|
|
"path"
|
|
|
"strconv"
|
|
|
)
|
|
|
|
|
|
type CommonTextToSpeechLogic struct {
|
|
|
logx.Logger
|
|
|
ctx context.Context
|
|
|
svcCtx *svc.ServiceContext
|
|
|
}
|
|
|
|
|
|
func NewCommonTextToSpeechLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CommonTextToSpeechLogic {
|
|
|
return &CommonTextToSpeechLogic{
|
|
|
Logger: logx.WithContext(ctx),
|
|
|
ctx: ctx,
|
|
|
svcCtx: svcCtx,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func (l *CommonTextToSpeechLogic) CommonTextToSpeech(req *types.TextToSpeechRequest) (resp *types.TextToSpeechResponse, err error) {
|
|
|
token, err := l.getToken1()
|
|
|
if err != nil {
|
|
|
return nil, xerr.NewErrMsgErr("授权失败", err)
|
|
|
}
|
|
|
id, _ := uuid.NewUUID()
|
|
|
file := fmt.Sprintf("%s.wav", id.String())
|
|
|
filename := path.Join("public", file)
|
|
|
if err = l.processPOSTRequest(token, req.Text, filename, "wav", 16000); err != nil {
|
|
|
return nil, xerr.NewErrMsgErr("TTS转换失败", err)
|
|
|
}
|
|
|
url := path.Join("file", file)
|
|
|
resp = &types.TextToSpeechResponse{
|
|
|
AudioUrl: url,
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
|
|
|
func (l *CommonTextToSpeechLogic) getToken() (string, error) {
|
|
|
client, err := sdk.NewClientWithAccessKey(l.svcCtx.Config.TTS.ReginID, l.svcCtx.Config.TTS.AccessKeyID, l.svcCtx.Config.TTS.AccessKeySecret)
|
|
|
if err != nil {
|
|
|
return "", xerr.NewErrMsgErr("授权失败", err)
|
|
|
}
|
|
|
request := requests.NewCommonRequest()
|
|
|
request.Method = "POST"
|
|
|
request.Domain = l.svcCtx.Config.TTS.Domain //"nlsmeta.ap-southeast-1.aliyuncs.com"
|
|
|
request.ApiName = "CreateToken"
|
|
|
request.Version = "2019-02-28"
|
|
|
response, err := client.ProcessCommonRequest(request)
|
|
|
|
|
|
if err != nil {
|
|
|
return "", xerr.NewErrMsgErr("授权失败", err)
|
|
|
}
|
|
|
token := response.GetHttpContentString()
|
|
|
return token, nil
|
|
|
}
|
|
|
|
|
|
func (l *CommonTextToSpeechLogic) getToken1() (string, error) {
|
|
|
tts := l.svcCtx.Config.TTS
|
|
|
client, err := nls.GetToken(tts.ReginID, tts.Domain, tts.AccessKeyID, tts.AccessKeySecret, "2019-02-28")
|
|
|
if err != nil {
|
|
|
return "", xerr.NewErrMsgErr("授权失败", err)
|
|
|
}
|
|
|
token := client.TokenResult.Id
|
|
|
return token, nil
|
|
|
}
|
|
|
|
|
|
func (l *CommonTextToSpeechLogic) processPOSTRequest(token string, text string, audioSaveFile string, format string, sampleRate int) error {
|
|
|
/**
|
|
|
* 设置HTTPS POST请求:
|
|
|
* 1.使用HTTPS协议
|
|
|
* 2.语音合成服务域名:nls-gateway-ap-southeast-1.aliyuncs.com
|
|
|
* 3.语音合成接口请求路径:/stream/v1/tts
|
|
|
* 4.设置必须请求参数:appkey、token、text、format、sample_rate
|
|
|
* 5.设置可选请求参数:voice、volume、speech_rate、pitch_rate
|
|
|
*/
|
|
|
ttsConfig := l.svcCtx.Config.TTS
|
|
|
var url string = fmt.Sprintf("https://%s/stream/v1/tts", "nls-gateway-ap-southeast-1.aliyuncs.com")
|
|
|
bodyContent := make(map[string]interface{})
|
|
|
bodyContent["appkey"] = ttsConfig.AppKey
|
|
|
bodyContent["text"] = text
|
|
|
bodyContent["token"] = token
|
|
|
bodyContent["format"] = format
|
|
|
bodyContent["sample_rate"] = sampleRate
|
|
|
// voice 发音人,可选,默认是xiaoyun。
|
|
|
bodyContent["voice"] = ttsConfig.Voice
|
|
|
// volume 音量,范围是0~100,可选,默认50。
|
|
|
bodyContent["volume"] = ttsConfig.Volume
|
|
|
// speech_rate 语速,范围是-500~500,可选,默认是0。
|
|
|
bodyContent["speech_rate"] = ttsConfig.SpeechRate
|
|
|
// pitch_rate 语调,范围是-500~500,可选,默认是0。
|
|
|
bodyContent["pitch_rate"] = ttsConfig.PitchRate
|
|
|
bodyJson, err := json.Marshal(bodyContent)
|
|
|
if err != nil {
|
|
|
panic(nil)
|
|
|
}
|
|
|
fmt.Println(string(bodyJson))
|
|
|
/**
|
|
|
* 发送HTTPS POST请求,处理服务端的响应。
|
|
|
*/
|
|
|
response, err := http.Post(url, "application/json;charset=utf-8", bytes.NewBuffer([]byte(bodyJson)))
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
defer response.Body.Close()
|
|
|
contentType := response.Header.Get("Content-Type")
|
|
|
body, _ := ioutil.ReadAll(response.Body)
|
|
|
var file *os.File
|
|
|
if "audio/mpeg" == contentType {
|
|
|
file, err = os.Create(audioSaveFile)
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
defer file.Close()
|
|
|
file.Write([]byte(body))
|
|
|
//fmt.Println("The POST request succeed!")
|
|
|
} else {
|
|
|
// ContentType 为 null 或者为 "application/json"
|
|
|
statusCode := response.StatusCode
|
|
|
fmt.Println("The HTTP statusCode: " + strconv.Itoa(statusCode))
|
|
|
fmt.Println("The POST request failed: " + string(body))
|
|
|
return xerr.NewErrMsgErr("The POST request failed: "+string(body), nil)
|
|
|
}
|
|
|
return nil
|
|
|
} |
...
|
...
|
|