You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

268 lines
8.8 KiB

package aliyun
import (
"encoding/json"
"errors"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"strconv"
"time"
)
const (
ALIYUN_CLOUND_REGION_CHA = 1 //中国
ALIYUN_CLOUND_REGION_INT = 2 //海外
)
//阿里云语音识别引擎
type AliyunClound struct {
AccessKeyId string
AccessKeySecret string
AppKey string
Region int
}
//阿里云录音文件识别结果集
type AliyunAudioRecognitionResult struct {
Text string //文本结果
TranslateText string //翻译文本结果
ChannelId int64 //音轨ID
BeginTime int64 //该句的起始时间偏移,单位为毫秒
EndTime int64 //该句的结束时间偏移,单位为毫秒
SilenceDuration int64 //本句与上一句之间的静音时长,单位为秒
SpeechRate int64 //本句的平均语速,单位为每分钟字数
EmotionValue int64 //情绪能量值1-10,值越高情绪越强烈
}
//阿里云识别词语数据集
type AliyunAudioWord struct {
Word string
ChannelId int64
BeginTime int64
EndTime int64
}
// 定义常量
const REGION_ID_REGION_INT string = "ap-southeast-1"
const ENDPOINT_NAME_REGION_INT string = "ap-southeast-1"
const PRODUCT_REGION_INT string = "nls-filetrans"
const DOMAIN_REGION_INT string = "filetrans.ap-southeast-1.aliyuncs.com"
const API_VERSION_REGION_INT string = "2019-08-23"
const REGION_ID_REGION_CHA string = "cn-shanghai"
const ENDPOINT_NAME_REGION_CHA string = "cn-shanghai"
const PRODUCT_REGION_CHA string = "nls-filetrans"
const DOMAIN_REGION_CHA string = "filetrans.cn-shanghai.aliyuncs.com"
const API_VERSION_REGION_CHA string = "2018-08-17"
const POST_REQUEST_ACTION string = "SubmitTask"
const GET_REQUEST_ACTION string = "GetTaskResult"
// 请求参数key
const KEY_APP_KEY string = "appkey"
const KEY_FILE_LINK string = "file_link"
const KEY_VERSION string = "version"
const KEY_ENABLE_WORDS string = "enable_words"
//是否打开ITN,中文数字将转为阿拉伯数字输出,默认值为false
const KEY_ENABLE_INVERSE_TEXT_NORMAL = "enable_inverse_text_normalization"
//是否启⽤语义断句,取值:true/false,默认值false
const KEY_ENABLE_SEMANTIC_SENTENCE_DETECTION = "enable_semantic_sentence_detection"
//是否启用时间戳校准功能,取值:true/false,默认值false
const KEY_ENABLE_TIMESTAMP_ALIGNMENT = "enable_timestamp_alignment"
// 响应参数key
const KEY_TASK string = "Task"
const KEY_TASK_ID string = "TaskId"
const KEY_STATUS_TEXT string = "StatusText"
const KEY_RESULT string = "Result"
// 状态值
const STATUS_SUCCESS string = "SUCCESS"
const STATUS_RUNNING string = "RUNNING"
const STATUS_QUEUEING string = "QUEUEING"
//发起录音文件识别
//接口文档 https://help.aliyun.com/document_detail/90727.html?spm=a2c4g.11186623.6.581.691af6ebYsUkd1
func (c AliyunClound) NewAudioFile(fileLink string) (string , *sdk.Client , error) {
regionId, domain, apiVersion, product := c.GetApiVariable()
client, err := sdk.NewClientWithAccessKey(regionId, c.AccessKeyId, c.AccessKeySecret)
if err != nil {
return "" , client , err
}
client.SetConnectTimeout(time.Second * 20)
postRequest := requests.NewCommonRequest()
postRequest.Domain = domain
postRequest.Version = apiVersion
postRequest.Product = product
postRequest.ApiName = POST_REQUEST_ACTION
postRequest.Method = "POST"
mapTask := make(map[string]string)
mapTask[KEY_APP_KEY] = c.AppKey
mapTask[KEY_FILE_LINK] = fileLink
// 新接入请使用4.0版本,已接入(默认2.0)如需维持现状,请注释掉该参数设置
mapTask[KEY_VERSION] = "4.0"
// 设置是否输出词信息,默认为false,开启时需要设置version为4.0
mapTask[KEY_ENABLE_WORDS] = "true"
//统一后处理
mapTask[KEY_ENABLE_INVERSE_TEXT_NORMAL] = "true"
mapTask[KEY_ENABLE_SEMANTIC_SENTENCE_DETECTION] = "true"
mapTask[KEY_ENABLE_TIMESTAMP_ALIGNMENT] = "true"
// to json
task, err := json.Marshal(mapTask)
if err != nil {
return "" , client , errors.New("to json error .")
}
postRequest.FormParams[KEY_TASK] = string(task)
// 发起请求
postResponse, err := client.ProcessCommonRequest(postRequest)
if err != nil {
return "" , client , err
}
postResponseContent := postResponse.GetHttpContentString()
//校验请求
if (postResponse.GetHttpStatus() != 200) {
return "" , client , errors.New("录音文件识别请求失败 , Http错误码 : " + strconv.Itoa(postResponse.GetHttpStatus()))
}
//解析数据
var postMapResult map[string]interface{}
err = json.Unmarshal([]byte(postResponseContent), &postMapResult)
if err != nil {
return "" , client , errors.New("to map struct error .")
}
var taskId = ""
var statusText = ""
statusText = postMapResult[KEY_STATUS_TEXT].(string)
//检验结果
if statusText == STATUS_SUCCESS {
taskId = postMapResult[KEY_TASK_ID].(string)
return taskId , client , nil
}
return "" , client , errors.New("录音文件识别失败 , (" + c.GetErrorStatusTextMessage(statusText) + ")")
}
//获取录音文件识别结果
//接口文档 https://help.aliyun.com/document_detail/90727.html?spm=a2c4g.11186623.6.581.691af6ebYsUkd1
func (c AliyunClound) GetAudioFileResult(taskId string , client *sdk.Client , logOutput func(text string) , callback func(result []byte)) (err error) {
_, domain, apiVersion, product := c.GetApiVariable()
getRequest := requests.NewCommonRequest()
getRequest.Domain = domain
getRequest.Version = apiVersion
getRequest.Product = product
getRequest.ApiName = GET_REQUEST_ACTION
getRequest.Method = "GET"
getRequest.QueryParams[KEY_TASK_ID] = taskId
statusText := ""
var (
trys = 0
getResponse *responses.CommonResponse
getResponseContent string
)
//遍历获取识别结果
for trys < 10 {
if trys != 0 {
logOutput("尝试重新查询识别结果,第" + strconv.Itoa(trys) + "次")
}
getResponse, err = client.ProcessCommonRequest(getRequest)
if err != nil {
logOutput("查询识别结果失败:" + err.Error())
trys++
time.Sleep(time.Second * time.Duration(trys))
continue
}
getResponseContent = getResponse.GetHttpContentString()
if (getResponse.GetHttpStatus() != 200) {
logOutput("查询识别结果失败,Http错误码:" + strconv.Itoa(getResponse.GetHttpStatus()))
trys++
time.Sleep(time.Second * time.Duration(trys))
continue
}
var getMapResult map[string]interface{}
err = json.Unmarshal([]byte(getResponseContent), &getMapResult)
if err != nil {
trys++
logOutput("查询识别结果失败,解析结果失败:" + err.Error())
continue
}
//校验遍历条件
statusText = getMapResult[KEY_STATUS_TEXT].(string)
if statusText == STATUS_RUNNING || statusText == STATUS_QUEUEING {
time.Sleep(3 * time.Second)
} else {
break
}
}
if statusText == STATUS_SUCCESS && getResponse != nil {
//调用回调函数
callback(getResponse.GetHttpContentBytes())
} else {
err = errors.New("录音文件识别失败 , (" + c.GetErrorStatusTextMessage(statusText) + ")")
return
}
return
}
//获取API常量
func (c AliyunClound) GetApiVariable () (regionId string , domain string , apiVersion string , product string) {
if c.Region == 0 || c.Region == ALIYUN_CLOUND_REGION_CHA {
regionId = REGION_ID_REGION_CHA
domain = DOMAIN_REGION_CHA
apiVersion = API_VERSION_REGION_CHA
product = PRODUCT_REGION_CHA
} else if c.Region == ALIYUN_CLOUND_REGION_INT {
regionId = REGION_ID_REGION_INT
domain = DOMAIN_REGION_INT
apiVersion = API_VERSION_REGION_INT
product = PRODUCT_REGION_INT
}
return
}
//获取错误信息
func (c AliyunClound) GetErrorStatusTextMessage (statusText string) string {
var code map[string]string = map[string]string{
"REQUEST_APPKEY_UNREGISTERED":"阿里云智能语音项目未创建/无访问权限。请检查语音引擎Appkey是否填写错误;如果是海外地区,在软件创建语音引擎时,服务区域需要选择“海外”",
"USER_BIZDURATION_QUOTA_EXCEED":"单日2小时识别免费额度超出限制",
"FILE_DOWNLOAD_FAILED":"文件访问失败,请检查OSS存储空间访问权限。请将OSS存储空间设置为“公共读”",
"FILE_TOO_LARGE":"音频文件超出512MB",
"FILE_PARSE_FAILED":"音频文件解析失败,请检查音频文件是否有损坏",
"UNSUPPORTED_SAMPLE_RATE":"采样率不匹配",
"FILE_TRANS_TASK_EXPIRED":"音频文件识别任务过期,请重试",
"REQUEST_INVALID_FILE_URL_VALUE":"音频文件访问失败,请检查OSS存储空间访问权限",
"FILE_404_NOT_FOUND":"音频文件访问失败,请检查OSS存储空间访问权限",
"FILE_403_FORBIDDEN":"音频文件访问失败,请检查OSS存储空间访问权限",
"FILE_SERVER_ERROR":"音频文件访问失败,请检查请求的文件所在的服务是否可用",
"INTERNAL_ERROR":"识别内部通用错误,请稍候重试",
}
if _, ok := code[statusText]; ok {
return code[statusText]
} else {
return statusText
}
}