hsun пре 1 година
родитељ
комит
e25dac2311

+ 102 - 70
controllers/speech_recognition/speech_recognition.go

@@ -6,9 +6,9 @@ import (
 	"eta/eta_api/models"
 	"eta/eta_api/models/speech_recognition"
 	"eta/eta_api/services"
+	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
 	"fmt"
-	"strconv"
 	"strings"
 	"time"
 )
@@ -21,61 +21,113 @@ type SpeechRecognitionCommonController struct {
 	controllers.BaseCommonController
 }
 
-// TODO:RecTaskCallback
+// RecTaskCallback
 // @Title 语音识别回调
 // @Description 语音识别回调
 // @Param	request	body services.TencentRecTaskCallback true "type json string"
 // @Success 200 string "操作成功"
 // @router /rec_task/callback [post]
 func (this *SpeechRecognitionCommonController) RecTaskCallback() {
-	utils.FileLog.Info("RecTaskCallback, -1")
 	// 此接口返回指定响应体
 	br := new(services.TencentRecTaskCallbackResp)
+	var errMsg string
 	defer func() {
+		if errMsg != "" {
+			br.Code = 403
+			br.Message = "回调失败"
+			go alarm_msg.SendAlarmMsg(fmt.Sprintf("语音识别回调失败, ErrMsg: %s", errMsg), 1)
+		} else {
+			br.Code = 0
+			br.Message = "success"
+		}
 		_ = this.JSON(br, false, false)
 	}()
-	var req services.TencentRecTaskCallback
-
-	utils.FileLog.Info("RecTaskCallback, 0")
 
-	code, _ := this.GetInt("code", 0)
-	req.Code = code
+	code, _ := this.GetInt("code", -1)
 	requestId, _ := this.GetInt("requestId", 0)
-	req.RequestId = uint64(requestId)
-	text := this.GetString("text")
-	req.Text = text
-	resultDetail := this.GetString("resultDetail")
-	req.ResultDetail = resultDetail
-
-	//utils.FileLog.Info("RecTaskCallback, body: " + string(this.Ctx.Input.RequestBody))
-	//if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
-	//	br.Code = 403
-	//	br.Message = "参数解析失败"
-	//	return
-	//}
-	utils.FileLog.Info("RecTaskCallback, 1")
-
-	// TODO:处理回调结果
-	apiLog := new(speech_recognition.SpeechRecognitionApiLog)
-	apiLog.RequestId = strconv.Itoa(int(req.RequestId))
-	j, e := json.Marshal(req)
+	detail := this.GetString("resultDetail")
+	utils.FileLog.Info(fmt.Sprintf("RecTaskCallback, requestId: %d", requestId))
+
+	// 获取taskId对应的API请求及语音识别
+	logOb := new(speech_recognition.SpeechRecognitionApiLog)
+	cond := fmt.Sprintf(` AND %s = ?`, speech_recognition.SpeechRecognitionApiLogCols.RequestId)
+	pars := make([]interface{}, 0)
+	pars = append(pars, requestId)
+	apiLog, e := logOb.GetItemByCondition(cond, pars, "")
 	if e != nil {
-		utils.FileLog.Info("RecTaskCallback, 2 " + e.Error())
+		errMsg = "获取API记录失败"
+		utils.FileLog.Info("API回调-获取请求记录失败, Err: " + e.Error())
+		return
 	}
-	apiLog.RequestResult = string(j)
-	apiLog.CreateTime = time.Now().Local()
-	apiLog.ModifyTime = time.Now().Local()
-	if e := apiLog.Create(); e != nil {
-		br.Code = 403
-		br.Message = "获取回调结果失败"
+	speechOb := new(speech_recognition.SpeechRecognition)
+	speechItem, e := speechOb.GetItemById(apiLog.SpeechRecognitionId)
+	if e != nil {
+		errMsg = "获取语音识别失败"
+		utils.FileLog.Info("获取语音识别失败, Err: " + e.Error())
+		return
+	}
+
+	// API结果返回有误
+	nowTime := time.Now().Local()
+	if code != speech_recognition.ApiRequestCodeSuccess {
+		convertRemark := speech_recognition.ApiErrMsgMapping[code]
+		if convertRemark == "" {
+			convertRemark = fmt.Sprintf("未知错误: %d", code)
+		}
+		speechItem.ConvertRemark = convertRemark
+		speechItem.State = speech_recognition.SpeechRecognitionStateFail
+		speechItem.ModifyTime = nowTime
+		speechCols := []string{speech_recognition.SpeechRecognitionCols.ConvertRemark, speech_recognition.SpeechRecognitionCols.State, speech_recognition.SpeechRecognitionCols.ModifyTime}
+
+		apiLog.RequestCode = code
+		apiLog.RequestResult = convertRemark
+		apiLog.ModifyTime = nowTime
+		apiLogCols := []string{speech_recognition.SpeechRecognitionApiLogCols.RequestCode, speech_recognition.SpeechRecognitionApiLogCols.RequestResult, speech_recognition.SpeechRecognitionApiLogCols.ModifyTime}
+
+		// 更新语音识别及API记录
+		if e := speech_recognition.UpdateSpeechAndApiLog(speechItem, speechCols, apiLog, apiLogCols); e != nil {
+			errMsg = "更新API返回结果失败"
+			utils.FileLog.Info("更新API返回结果失败, Err: " + e.Error())
+		}
+		return
+	}
+
+	// 解析转写段落内容
+	sentences := make([]*services.TencentRecTaskSentenceDetail, 0)
+	if e := json.Unmarshal([]byte(detail), &sentences); e != nil {
+		errMsg = "解析语音识别内容失败"
+		utils.FileLog.Info("解析语音识别内容失败, Err: " + e.Error())
 		return
 	}
-	utils.FileLog.Info("RecTaskCallback, 3")
+	contents := make([]*speech_recognition.SpeechRecognitionContent, 0)
+	sorts := 0 // API返回的结果本身是已排过序的
+	for _, v := range sentences {
+		sorts += 1
+		t := new(speech_recognition.SpeechRecognitionContent)
+		t.SpeechRecognitionId = speechItem.SpeechRecognitionId
+		t.Sort = sorts
+		t.Content = v.FinalSentence
+		t.StartMs = v.StartMs
+		t.EndMs = v.EndMs
+		t.CreateTime = nowTime
+		t.ModifyTime = nowTime
+		contents = append(contents, t)
+	}
+
+	speechItem.State = speech_recognition.SpeechRecognitionStateSuccess
+	speechItem.ModifyTime = nowTime
+	speechCols := []string{speech_recognition.SpeechRecognitionCols.State, speech_recognition.SpeechRecognitionCols.ModifyTime}
 
-	// TODO:更新语音识别状态及内容
+	apiLog.RequestCode = code
+	apiLog.RequestResult = detail
+	apiLog.ModifyTime = time.Now().Local()
+	apiLogCols := []string{speech_recognition.SpeechRecognitionApiLogCols.RequestCode, speech_recognition.SpeechRecognitionApiLogCols.RequestResult, speech_recognition.SpeechRecognitionApiLogCols.ModifyTime}
 
-	br.Code = 0
-	br.Message = "success"
+	// 新增解析内容并更新语音识别及API记录
+	if e := speech_recognition.CreateContentAndUpdateSpeechAndApiLog(contents, speechItem, speechCols, apiLog, apiLogCols); e != nil {
+		errMsg = "新增API返回结果失败"
+		utils.FileLog.Info("新增API返回结果失败, Err: " + e.Error())
+	}
 }
 
 // Convert
@@ -134,14 +186,14 @@ func (this *SpeechRecognitionController) Convert() {
 		t.State = speech_recognition.SpeechRecognitionStateWait
 		t.CreateTime = nowTime
 		t.ModifyTime = nowTime
+		// CreateMulti拿不到主键, 此处用循环新增获取
+		if e := t.Create(); e != nil {
+			br.Msg = "操作失败"
+			br.ErrMsg = "批量新增转写文件失败, Err: " + e.Error()
+			return
+		}
 		speeches = append(speeches, t)
 	}
-	speechOb := new(speech_recognition.SpeechRecognition)
-	if e := speechOb.CreateMulti(speeches); e != nil {
-		br.Msg = "操作失败"
-		br.ErrMsg = "批量新增转写文件失败, Err: " + e.Error()
-		return
-	}
 
 	// 批量转写语音
 	go func() {
@@ -213,13 +265,13 @@ func (this *SpeechRecognitionController) Save() {
 		this.Data["json"] = br
 		this.ServeJSON()
 	}()
-	//sysUser := this.SysUser
-	//if sysUser == nil {
-	//	br.Msg = "请登录"
-	//	br.ErrMsg = "请登录,SysUser Is Empty"
-	//	br.Ret = 408
-	//	return
-	//}
+	sysUser := this.SysUser
+	if sysUser == nil {
+		br.Msg = "请登录"
+		br.ErrMsg = "请登录,SysUser Is Empty"
+		br.Ret = 408
+		return
+	}
 	var req speech_recognition.SpeechRecognitionSaveReq
 	if e := json.Unmarshal(this.Ctx.Input.RequestBody, &req); e != nil {
 		br.Msg = "参数有误"
@@ -227,26 +279,6 @@ func (this *SpeechRecognitionController) Save() {
 		return
 	}
 
-	conf, e := models.GetBusinessConf()
-	if e != nil {
-		br.Msg = "操作失败"
-		br.ErrMsg = "获取配置失败, Err: " + e.Error()
-		return
-	}
-
-	var taskReq services.TencentRecTaskReq
-	taskReq.FileUrl = req.FileName
-	taskReq.SecretId = conf[models.BusinessConfTencentApiSecretId]
-	taskReq.SecretKey = conf[models.BusinessConfTencentApiSecretKey]
-	taskReq.CallbackUrl = conf[models.BusinessConfTencentApiRecTaskCallbackUrl]
-	taskId, e := services.TencentCreateRecTask(taskReq)
-	if e != nil {
-		br.Msg = "操作失败"
-		br.ErrMsg = fmt.Sprintf("TencentCreateRecTask err: %s", e.Error())
-		return
-	}
-
-	br.Data = taskId
 	br.Ret = 200
 	br.Success = true
 	br.Msg = "操作成功"

+ 8 - 8
controllers/speech_recognition/speech_recognition_menu.go

@@ -52,7 +52,7 @@ func (this *SpeechRecognitionMenuController) Add() {
 	// 校验同级目录是否有重名
 	menuOb := new(speech_recognition.SpeechRecognitionMenu)
 	{
-		cond := fmt.Sprintf(` %s = ? AND %s = ?`, speech_recognition.SpeechRecognitionMenuCols.MenuName, speech_recognition.SpeechRecognitionMenuCols.ParentId)
+		cond := fmt.Sprintf(` AND %s = ? AND %s = ?`, speech_recognition.SpeechRecognitionMenuCols.MenuName, speech_recognition.SpeechRecognitionMenuCols.ParentId)
 		pars := make([]interface{}, 0)
 		pars = append(pars, req.MenuName, req.ParentId)
 		exists, e := menuOb.GetItemByCondition(cond, pars, "")
@@ -151,7 +151,7 @@ func (this *SpeechRecognitionMenuController) Edit() {
 
 	// 校验同级目录是否有重名
 	{
-		cond := fmt.Sprintf(` %s = ? AND %s = ? AND %s <> ?`, speech_recognition.SpeechRecognitionMenuCols.MenuName, speech_recognition.SpeechRecognitionMenuCols.ParentId, speech_recognition.SpeechRecognitionMenuCols.SpeechRecognitionMenuId)
+		cond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s <> ?`, speech_recognition.SpeechRecognitionMenuCols.MenuName, speech_recognition.SpeechRecognitionMenuCols.ParentId, speech_recognition.SpeechRecognitionMenuCols.SpeechRecognitionMenuId)
 		pars := make([]interface{}, 0)
 		pars = append(pars, req.MenuName, menuItem.ParentId, req.MenuId)
 		exists, e := menuOb.GetItemByCondition(cond, pars, "")
@@ -231,7 +231,7 @@ func (this *SpeechRecognitionMenuController) Remove() {
 	// 校验目录下是否有内容
 	{
 		speechOb := new(speech_recognition.SpeechRecognition)
-		cond := fmt.Sprintf(` %s = ?`, speech_recognition.SpeechRecognitionCols.MenuId)
+		cond := fmt.Sprintf(` AND %s = ?`, speech_recognition.SpeechRecognitionCols.MenuId)
 		pars := make([]interface{}, 0)
 		pars = append(pars, req.MenuId)
 		count, e := speechOb.GetCountByCondition(cond, pars)
@@ -245,7 +245,7 @@ func (this *SpeechRecognitionMenuController) Remove() {
 			return
 		}
 
-		cond = fmt.Sprintf(` %s = ?`, speech_recognition.SpeechRecognitionMenuCols.ParentId)
+		cond = fmt.Sprintf(` AND %s = ?`, speech_recognition.SpeechRecognitionMenuCols.ParentId)
 		pars = make([]interface{}, 0)
 		pars = append(pars, req.MenuId)
 		count, e = menuOb.GetCountByCondition(cond, pars)
@@ -299,7 +299,7 @@ func (this *SpeechRecognitionMenuController) Tree() {
 	menus := make([]*speech_recognition.SpeechRecognitionMenu, 0)
 	{
 		menuOb := new(speech_recognition.SpeechRecognitionMenu)
-		cond := fmt.Sprintf(` %s = ?`, speech_recognition.SpeechRecognitionMenuCols.ParentId)
+		cond := fmt.Sprintf(` AND %s = ?`, speech_recognition.SpeechRecognitionMenuCols.ParentId)
 		pars := make([]interface{}, 0)
 		pars = append(pars, parentId)
 		list, e := menuOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", speech_recognition.SpeechRecognitionMenuCols.Sort))
@@ -328,7 +328,7 @@ func (this *SpeechRecognitionMenuController) Tree() {
 	childMenus := make([]*speech_recognition.SpeechRecognitionMenu, 0)
 	{
 		menuOb := new(speech_recognition.SpeechRecognitionMenu)
-		cond := fmt.Sprintf(` %s IN (%s)`, speech_recognition.SpeechRecognitionMenuCols.ParentId, utils.GetOrmInReplace(len(menuIds)))
+		cond := fmt.Sprintf(` AND %s IN (%s)`, speech_recognition.SpeechRecognitionMenuCols.ParentId, utils.GetOrmInReplace(len(menuIds)))
 		pars := make([]interface{}, 0)
 		pars = append(pars, menuIds)
 		list, e := menuOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC, %s ASC", speech_recognition.SpeechRecognitionMenuCols.Sort, speech_recognition.SpeechRecognitionMenuCols.ParentId))
@@ -337,7 +337,7 @@ func (this *SpeechRecognitionMenuController) Tree() {
 			br.ErrMsg = "获取子目录列表失败, Err: " + e.Error()
 			return
 		}
-		menus = list
+		childMenus = list
 	}
 	menuChildren := make(map[int][]*speech_recognition.SpeechRecognitionMenuNodeItem)
 	for _, m := range childMenus {
@@ -358,7 +358,7 @@ func (this *SpeechRecognitionMenuController) Tree() {
 	speeches := make([]*speech_recognition.SpeechRecognition, 0)
 	{
 		speechOb := new(speech_recognition.SpeechRecognition)
-		cond := fmt.Sprintf(` %s IN (%s)`, speech_recognition.SpeechRecognitionCols.MenuId, utils.GetOrmInReplace(len(menuIds)))
+		cond := fmt.Sprintf(` AND %s IN (%s)`, speech_recognition.SpeechRecognitionCols.MenuId, utils.GetOrmInReplace(len(menuIds)))
 		pars := make([]interface{}, 0)
 		pars = append(pars, menuIds)
 		list, e := speechOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC, %s DESC", speech_recognition.SpeechRecognitionCols.Sort, speech_recognition.SpeechRecognitionCols.CreateTime))

+ 8 - 8
controllers/speech_recognition/speech_recognition_tag_menu.go

@@ -54,7 +54,7 @@ func (this *SpeechRecognitionTagMenuController) Add() {
 	// 校验同级目录是否有重名
 	menuOb := new(speech_recognition.SpeechRecognitionTagMenu)
 	{
-		cond := fmt.Sprintf(` %s = ? AND %s = ?`, speech_recognition.SpeechRecognitionTagMenuCols.MenuName, speech_recognition.SpeechRecognitionTagMenuCols.ParentId)
+		cond := fmt.Sprintf(` AND %s = ? AND %s = ?`, speech_recognition.SpeechRecognitionTagMenuCols.MenuName, speech_recognition.SpeechRecognitionTagMenuCols.ParentId)
 		pars := make([]interface{}, 0)
 		pars = append(pars, req.MenuName, req.ParentId)
 		exists, e := menuOb.GetItemByCondition(cond, pars, "")
@@ -153,7 +153,7 @@ func (this *SpeechRecognitionTagMenuController) Edit() {
 
 	// 校验同级目录是否有重名
 	{
-		cond := fmt.Sprintf(` %s = ? AND %s = ? AND %s <> ?`, speech_recognition.SpeechRecognitionTagMenuCols.MenuName, speech_recognition.SpeechRecognitionTagMenuCols.ParentId, speech_recognition.SpeechRecognitionTagMenuCols.SpeechRecognitionTagMenuId)
+		cond := fmt.Sprintf(` AND %s = ? AND %s = ? AND %s <> ?`, speech_recognition.SpeechRecognitionTagMenuCols.MenuName, speech_recognition.SpeechRecognitionTagMenuCols.ParentId, speech_recognition.SpeechRecognitionTagMenuCols.SpeechRecognitionTagMenuId)
 		pars := make([]interface{}, 0)
 		pars = append(pars, req.MenuName, menuItem.ParentId, req.MenuId)
 		exists, e := menuOb.GetItemByCondition(cond, pars, "")
@@ -233,7 +233,7 @@ func (this *SpeechRecognitionTagMenuController) Remove() {
 	// 校验目录下是否有内容
 	{
 		tagOb := new(speech_recognition.SpeechRecognitionTag)
-		cond := fmt.Sprintf(` %s = ?`, speech_recognition.SpeechRecognitionTagCols.MenuId)
+		cond := fmt.Sprintf(` AND %s = ?`, speech_recognition.SpeechRecognitionTagCols.MenuId)
 		pars := make([]interface{}, 0)
 		pars = append(pars, req.MenuId)
 		count, e := tagOb.GetCountByCondition(cond, pars)
@@ -247,7 +247,7 @@ func (this *SpeechRecognitionTagMenuController) Remove() {
 			return
 		}
 
-		cond = fmt.Sprintf(` %s = ?`, speech_recognition.SpeechRecognitionTagMenuCols.ParentId)
+		cond = fmt.Sprintf(` AND %s = ?`, speech_recognition.SpeechRecognitionTagMenuCols.ParentId)
 		pars = make([]interface{}, 0)
 		pars = append(pars, req.MenuId)
 		count, e = menuOb.GetCountByCondition(cond, pars)
@@ -301,7 +301,7 @@ func (this *SpeechRecognitionTagMenuController) Tree() {
 	menus := make([]*speech_recognition.SpeechRecognitionTagMenu, 0)
 	{
 		menuOb := new(speech_recognition.SpeechRecognitionTagMenu)
-		cond := fmt.Sprintf(` %s = ?`, speech_recognition.SpeechRecognitionTagMenuCols.ParentId)
+		cond := fmt.Sprintf(` AND %s = ?`, speech_recognition.SpeechRecognitionTagMenuCols.ParentId)
 		pars := make([]interface{}, 0)
 		pars = append(pars, parentId)
 		list, e := menuOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC", speech_recognition.SpeechRecognitionTagMenuCols.Sort))
@@ -330,7 +330,7 @@ func (this *SpeechRecognitionTagMenuController) Tree() {
 	childMenus := make([]*speech_recognition.SpeechRecognitionTagMenu, 0)
 	{
 		menuOb := new(speech_recognition.SpeechRecognitionTagMenu)
-		cond := fmt.Sprintf(` %s IN (%s)`, speech_recognition.SpeechRecognitionTagMenuCols.ParentId, utils.GetOrmInReplace(len(menuIds)))
+		cond := fmt.Sprintf(` AND %s IN (%s)`, speech_recognition.SpeechRecognitionTagMenuCols.ParentId, utils.GetOrmInReplace(len(menuIds)))
 		pars := make([]interface{}, 0)
 		pars = append(pars, menuIds)
 		list, e := menuOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC, %s ASC", speech_recognition.SpeechRecognitionTagMenuCols.Sort, speech_recognition.SpeechRecognitionTagMenuCols.ParentId))
@@ -339,7 +339,7 @@ func (this *SpeechRecognitionTagMenuController) Tree() {
 			br.ErrMsg = "获取子目录列表失败, Err: " + e.Error()
 			return
 		}
-		menus = list
+		childMenus = list
 	}
 	menuChildren := make(map[int][]*speech_recognition.SpeechRecognitionTagMenuNodeItem)
 	for _, m := range childMenus {
@@ -360,7 +360,7 @@ func (this *SpeechRecognitionTagMenuController) Tree() {
 	tags := make([]*speech_recognition.SpeechRecognitionTag, 0)
 	{
 		tagOb := new(speech_recognition.SpeechRecognitionTag)
-		cond := fmt.Sprintf(` %s IN (%s)`, speech_recognition.SpeechRecognitionTagCols.MenuId, utils.GetOrmInReplace(len(menuIds)))
+		cond := fmt.Sprintf(` AND %s IN (%s)`, speech_recognition.SpeechRecognitionTagCols.MenuId, utils.GetOrmInReplace(len(menuIds)))
 		pars := make([]interface{}, 0)
 		pars = append(pars, menuIds)
 		list, e := tagOb.GetItemsByCondition(cond, pars, []string{}, fmt.Sprintf("%s ASC, %s DESC", speech_recognition.SpeechRecognitionTagMenuCols.Sort, speech_recognition.SpeechRecognitionTagMenuCols.CreateTime))

+ 73 - 2
models/speech_recognition/speech_recognition.go

@@ -29,7 +29,7 @@ type SpeechRecognition struct {
 	Abstract            string    `description:"摘要,取前几段内容"`
 	Sort                int       `description:"目录下的排序"`
 	FileState           int       `description:"文件(非语音识别)删除状态:0-正常;1-删除(该字段作为软删标识)"`
-	ConvertRemark       int       `description:"转写备注-失败原因"`
+	ConvertRemark       string    `description:"转写备注-失败原因"`
 	CreateTime          time.Time `description:"创建时间"`
 	ModifyTime          time.Time `description:"修改时间"`
 }
@@ -183,7 +183,7 @@ type SpeechRecognitionItem struct {
 	State               int    `description:"状态:1-待转换;2-转换完成;3-转换失败"`
 	Abstract            string `description:"摘要,取前几段内容"`
 	Sort                int    `description:"目录下的排序"`
-	ConvertRemark       int    `description:"转写备注-失败原因"`
+	ConvertRemark       string `description:"转写备注-失败原因"`
 	CreateTime          string `description:"创建时间"`
 	ModifyTime          string `description:"修改时间"`
 }
@@ -250,3 +250,74 @@ type SpeechRecognitionConvertFiles struct {
 	FileName    string `description:"文件名称"`
 	ResourceUrl string `description:"文件地址"`
 }
+
+// UpdateSpeechAndApiLog 更新语音识别及API记录
+func UpdateSpeechAndApiLog(speechItem *SpeechRecognition, speechCols []string, apiLogItem *SpeechRecognitionApiLog, logCols []string) (err error) {
+	if speechItem == nil || apiLogItem == nil {
+		err = fmt.Errorf("speechItem nil or apiLogItem nil")
+		return
+	}
+	o := orm.NewOrm()
+	tx, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+		} else {
+			_ = tx.Commit()
+		}
+	}()
+
+	_, e := tx.Update(speechItem, speechCols...)
+	if e != nil {
+		err = fmt.Errorf("update speech err: %s", e.Error())
+		return
+	}
+	_, e = tx.Update(apiLogItem, logCols...)
+	if e != nil {
+		err = fmt.Errorf("update api log err: %s", e.Error())
+		return
+	}
+	return
+}
+
+// CreateContentAndUpdateSpeechAndApiLog 新增语音识别内容并更新语音识别及API记录
+func CreateContentAndUpdateSpeechAndApiLog(contents []*SpeechRecognitionContent, speechItem *SpeechRecognition, speechCols []string, apiLogItem *SpeechRecognitionApiLog, logCols []string) (err error) {
+	if speechItem == nil || apiLogItem == nil {
+		err = fmt.Errorf("speechItem nil or apiLogItem nil")
+		return
+	}
+	o := orm.NewOrm()
+	tx, err := o.Begin()
+	if err != nil {
+		return
+	}
+	defer func() {
+		if err != nil {
+			_ = tx.Rollback()
+		} else {
+			_ = tx.Commit()
+		}
+	}()
+
+	_, e := tx.Update(speechItem, speechCols...)
+	if e != nil {
+		err = fmt.Errorf("update speech err: %s", e.Error())
+		return
+	}
+	_, e = tx.Update(apiLogItem, logCols...)
+	if e != nil {
+		err = fmt.Errorf("update api log err: %s", e.Error())
+		return
+	}
+	if len(contents) > 0 {
+		_, e = tx.InsertMulti(len(contents), contents)
+		if e != nil {
+			err = fmt.Errorf("insert multi contents err: %s", e.Error())
+			return
+		}
+	}
+	return
+}

+ 19 - 0
models/speech_recognition/speech_recognition_api_log.go

@@ -8,11 +8,28 @@ import (
 	"time"
 )
 
+const (
+	ApiRequestCodeSuccess = 0 // API成功状态码
+)
+
+// ApiErrMsgMapping API请求结果状态码对应错误提示
+var ApiErrMsgMapping = map[int]string{
+	10000: "转码失败,请确认音频格式是否符合标准",
+	10001: "识别失败",
+	10002: "语音时长太短",
+	10003: "语音时长太长",
+	10004: "无效的语音文件",
+	10005: "其他失败",
+	10006: "音轨个数不匹配",
+	10007: "音频下载失败",
+}
+
 // SpeechRecognitionApiLog 语音识别-API请求日志
 type SpeechRecognitionApiLog struct {
 	Id                  int       `orm:"column(id);pk"`
 	SpeechRecognitionId int       `description:"报告类型:1-中文研报;2-英文研报;3-智能研报"`
 	RequestId           string    `description:"API请求的唯一标识TaskId"`
+	RequestCode         int       `description:"API请求结果状态码:-1-待请求;0-成功;其他-失败"`
 	RequestResult       string    `description:"API请求结果-JSON"`
 	CreateTime          time.Time `description:"创建时间"`
 	ModifyTime          time.Time `description:"修改时间"`
@@ -22,6 +39,7 @@ var SpeechRecognitionApiLogCols = struct {
 	Id                  string
 	SpeechRecognitionId string
 	RequestId           string
+	RequestCode         string
 	RequestResult       string
 	CreateTime          string
 	ModifyTime          string
@@ -29,6 +47,7 @@ var SpeechRecognitionApiLogCols = struct {
 	Id:                  "id",
 	SpeechRecognitionId: "speech_recognition_id",
 	RequestId:           "request_id",
+	RequestCode:         "request_code",
 	RequestResult:       "request_result",
 	CreateTime:          "create_time",
 	ModifyTime:          "modify_time",

+ 145 - 0
models/speech_recognition/speech_recognition_content.go

@@ -1,4 +1,149 @@
 package speech_recognition
 
+import (
+	"eta/eta_api/utils"
+	"fmt"
+	"github.com/beego/beego/v2/client/orm"
+	"strings"
+	"time"
+)
+
+// SpeechRecognitionContent 语音识别-内容表
 type SpeechRecognitionContent struct {
+	SpeechRecognitionContentId int       `orm:"column(speech_recognition_content_id);pk"`
+	SpeechRecognitionId        int       `description:"语音识别ID"`
+	Sort                       int       `description:"段落排序"`
+	Content                    string    `description:"段落内容"`
+	StartMs                    int       `description:"单句开始时间(毫秒)"`
+	EndMs                      int       `description:"单句结束时间(毫秒)"`
+	IsUpdate                   int       `description:"是否手动修改过:0-否;1-是"`
+	CreateTime                 time.Time `description:"创建时间"`
+	ModifyTime                 time.Time `description:"修改时间"`
+}
+
+var SpeechRecognitionContentCols = struct {
+	SpeechRecognitionContentId string
+	SpeechRecognitionId        string
+	Sort                       string
+	Content                    string
+	StartMs                    string
+	EndMs                      string
+	IsUpdate                   string
+	CreateTime                 string
+	ModifyTime                 string
+}{
+	SpeechRecognitionContentId: "speech_recognition_content_id",
+	SpeechRecognitionId:        "speech_recognition_id",
+	Sort:                       "sort",
+	Content:                    "content",
+	StartMs:                    "start_ms",
+	EndMs:                      "end_ms",
+	IsUpdate:                   "is_update",
+	CreateTime:                 "create_time",
+	ModifyTime:                 "modify_time",
+}
+
+func (m *SpeechRecognitionContent) TableName() string {
+	return "speech_recognition_content"
+}
+
+func (m *SpeechRecognitionContent) PrimaryId() string {
+	return SpeechRecognitionContentCols.SpeechRecognitionContentId
+}
+
+func (m *SpeechRecognitionContent) Create() (err error) {
+	o := orm.NewOrm()
+	id, err := o.Insert(m)
+	if err != nil {
+		return
+	}
+	m.SpeechRecognitionContentId = int(id)
+	return
+}
+
+func (m *SpeechRecognitionContent) CreateMulti(items []*SpeechRecognitionContent) (err error) {
+	if len(items) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func (m *SpeechRecognitionContent) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(m, cols...)
+	return
+}
+
+func (m *SpeechRecognitionContent) Del() (err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	_, err = o.Raw(sql, m.SpeechRecognitionContentId).Exec()
+	return
+}
+
+func (m *SpeechRecognitionContent) MultiDel(menuIds []int) (err error) {
+	if len(menuIds) == 0 {
+		return
+	}
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`DELETE FROM %s WHERE %s IN (%s)`, m.TableName(), m.PrimaryId(), utils.GetOrmInReplace(len(menuIds)))
+	_, err = o.Raw(sql, menuIds).Exec()
+	return
+}
+
+func (m *SpeechRecognitionContent) GetItemById(id int) (item *SpeechRecognitionContent, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE %s = ? LIMIT 1`, m.TableName(), m.PrimaryId())
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+func (m *SpeechRecognitionContent) GetItemByCondition(condition string, pars []interface{}, orderRule string) (item *SpeechRecognitionContent, err error) {
+	o := orm.NewOrm()
+	order := ``
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT * FROM %s WHERE 1=1 %s %s LIMIT 1`, m.TableName(), condition, order)
+	err = o.Raw(sql, pars).QueryRow(&item)
+	return
+}
+
+func (m *SpeechRecognitionContent) GetCountByCondition(condition string, pars []interface{}) (count int, err error) {
+	o := orm.NewOrm()
+	sql := fmt.Sprintf(`SELECT COUNT(1) FROM %s WHERE 1=1 %s`, m.TableName(), condition)
+	err = o.Raw(sql, pars).QueryRow(&count)
+	return
+}
+
+func (m *SpeechRecognitionContent) GetItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string) (items []*SpeechRecognitionContent, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars).QueryRows(&items)
+	return
+}
+
+func (m *SpeechRecognitionContent) GetPageItemsByCondition(condition string, pars []interface{}, fieldArr []string, orderRule string, startSize, pageSize int) (items []*SpeechRecognitionContent, err error) {
+	o := orm.NewOrm()
+	fields := strings.Join(fieldArr, ",")
+	if len(fieldArr) == 0 {
+		fields = `*`
+	}
+	order := `ORDER BY create_time DESC`
+	if orderRule != "" {
+		order = ` ORDER BY ` + orderRule
+	}
+	sql := fmt.Sprintf(`SELECT %s FROM %s WHERE 1=1 %s %s LIMIT ?,?`, fields, m.TableName(), condition, order)
+	_, err = o.Raw(sql, pars, startSize, pageSize).QueryRows(&items)
+	return
 }

+ 84 - 1
services/speech_recognition.go

@@ -1,8 +1,14 @@
 package services
 
 import (
+	"eta/eta_api/models"
 	"eta/eta_api/models/speech_recognition"
+	"eta/eta_api/services/alarm_msg"
 	"eta/eta_api/utils"
+	"fmt"
+	"strconv"
+	"sync"
+	"time"
 )
 
 // GetSpeechRecognitionTagMenuTreeRecursive 递归获取标签目录树
@@ -24,7 +30,84 @@ func GetSpeechRecognitionTagMenuTreeRecursive(list []*speech_recognition.SpeechR
 	return res
 }
 
-// TODO:BatchConvertSpeech 批量转写语音
+// BatchConvertSpeech 批量转写语音
 func BatchConvertSpeech(speeches []*speech_recognition.SpeechRecognition) {
+	var err error
+	defer func() {
+		if err != nil {
+			tips := fmt.Sprintf("批量转写语音失败, ErrMsg: %s", err.Error())
+			utils.FileLog.Info(tips)
+			go alarm_msg.SendAlarmMsg(tips, 1)
+		}
+	}()
+
+	conf, e := models.GetBusinessConf()
+	if e != nil {
+		err = fmt.Errorf("获取配置失败, Err: %s", e.Error())
+		return
+	}
+	if conf[models.BusinessConfTencentApiSecretId] == "" || conf[models.BusinessConfTencentApiSecretKey] == "" || conf[models.BusinessConfTencentApiRecTaskCallbackUrl] == "" {
+		err = fmt.Errorf("API配置有误, SecretId: %s, SecretKey: %s, Callback: %s", conf[models.BusinessConfTencentApiSecretId], conf[models.BusinessConfTencentApiSecretKey], conf[models.BusinessConfTencentApiRecTaskCallbackUrl])
+		return
+	}
+
+	// 限制接口请求频率
+	apiLimit := make(chan struct{}, 20)
+	var wg sync.WaitGroup
+
+	for _, v := range speeches {
+		wg.Add(1)
+
+		go func(speech *speech_recognition.SpeechRecognition) {
+			defer func() {
+				wg.Done()
+				<-apiLimit
+			}()
+			apiLimit <- struct{}{}
+
+			// 发起请求
+			var errMsg string
+			var r TencentRecTaskReq
+			r.FileUrl = speech.ResourceUrl
+			r.SecretId = conf[models.BusinessConfTencentApiSecretId]
+			r.SecretKey = conf[models.BusinessConfTencentApiSecretKey]
+			r.CallbackUrl = conf[models.BusinessConfTencentApiRecTaskCallbackUrl]
+			taskId, e := TencentCreateRecTask(r)
+			if e != nil {
+				errMsg = "创建语音识别任务失败"
+				utils.FileLog.Info("TencentCreateRecTask创建语音识别任务失败, ErrMsg: %s", e.Error())
+			}
+
+			if errMsg == "" {
+				apiLog := new(speech_recognition.SpeechRecognitionApiLog)
+				apiLog.SpeechRecognitionId = speech.SpeechRecognitionId
+				apiLog.RequestId = strconv.Itoa(taskId)
+				apiLog.RequestCode = -1
+				apiLog.CreateTime = time.Now().Local()
+				apiLog.ModifyTime = time.Now().Local()
+				if e = apiLog.Create(); e != nil {
+					errMsg = "生成API请求失败"
+					utils.FileLog.Info("CreateApiLog生成API请求记录失败, ErrMsg: %s", e.Error())
+					return
+				}
+			}
+
+			// 有报错则更新对应语音识别状态
+			if errMsg == "" {
+				return
+			}
+			speech.State = speech_recognition.SpeechRecognitionStateFail
+			speech.ConvertRemark = errMsg
+			speech.ModifyTime = time.Now().Local()
+			updateCols := []string{speech_recognition.SpeechRecognitionCols.State, speech_recognition.SpeechRecognitionCols.ConvertRemark, speech_recognition.SpeechRecognitionCols.ModifyTime}
+			if e = speech.Update(updateCols); e != nil {
+				utils.FileLog.Info("UpdateSpeech更新语音识别状态失败, ErrMsg: %s", e.Error())
+				return
+			}
+		}(v)
+	}
+
+	wg.Wait()
+
 	return
 }

+ 7 - 0
services/tecent_asr.go → services/tencent_asr.go

@@ -81,3 +81,10 @@ type TencentRecTaskCallbackResp struct {
 	Code    int    `description:"0为成功, 其他值代表失败"`
 	Message string `description:"失败原因说明"`
 }
+
+// TencentRecTaskSentenceDetail 录音识别相应结果-单句详情
+type TencentRecTaskSentenceDetail struct {
+	FinalSentence string `description:"单句最终结果"`
+	StartMs       int    `description:"单句开始时间(毫秒)"`
+	EndMs         int    `description:"单句结束时间(毫秒)"`
+}