package services import ( "baliance.com/gooxml/document" "baliance.com/gooxml/measurement" "baliance.com/gooxml/schema/soo/wml" "bufio" "eta/eta_api/models" "eta/eta_api/models/speech_recognition" "eta/eta_api/services/alarm_msg" "eta/eta_api/utils" "fmt" "github.com/jung-kurt/gofpdf" "os" "strconv" "sync" "time" ) const ( SpeechRecognitionExportTypeTxt = 1 SpeechRecognitionExportTypeDocx = 2 SpeechRecognitionExportTypePdf = 3 ) // GetSpeechRecognitionTagMenuTreeRecursive 递归获取标签目录树 func GetSpeechRecognitionTagMenuTreeRecursive(list []*speech_recognition.SpeechRecognitionTagMenu, parentId int) []*speech_recognition.SpeechRecognitionTagMenuItem { res := make([]*speech_recognition.SpeechRecognitionTagMenuItem, 0) for _, v := range list { if v.ParentId == parentId { t := new(speech_recognition.SpeechRecognitionTagMenuItem) t.MenuId = v.SpeechRecognitionTagMenuId t.MenuName = v.MenuName t.ParentId = v.ParentId t.Level = v.Level t.Sort = v.Sort t.CreateTime = utils.TimeTransferString(utils.FormatDateTime, v.CreateTime) t.Children = GetSpeechRecognitionTagMenuTreeRecursive(list, v.SpeechRecognitionTagMenuId) res = append(res, t) } } return res } // 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 } // SpeechRecognitionContentExport 导出语音识别内容 func SpeechRecognitionContentExport(exportType int, exportTimestamp bool, fileName string, contents []*speech_recognition.SpeechRecognitionContent) (result string, err error) { defer func() { if err != nil { fmt.Println(err) } }() if len(contents) == 0 { return } // 整理内容 exportText := "" exportArr := make([]string, 0) exportPdfArr := make([]string, 0) for _, v := range contents { if v.Content == "" { continue } sec := "" secPdf := "" if exportTimestamp { // 毫秒转时间格式 sec = fmt.Sprintf("%s\n%s\n\n", utils.MillisecondsToHHMMSS(v.StartMs), v.Content) secPdf = fmt.Sprintf("%s %s", utils.MillisecondsToHHMMSS(v.StartMs), v.Content) } else { sec = fmt.Sprintf("%s\n\n", v.Content) secPdf = v.Content } exportText += sec exportArr = append(exportArr, sec) exportPdfArr = append(exportPdfArr, secPdf) } // 导出doc if exportType == SpeechRecognitionExportTypeDocx { doc := document.New() for _, v := range exportArr { p := doc.AddParagraph() prop := p.Properties() prop.Spacing().SetLineSpacing(measurement.Distance(1.5*15*measurement.Point), wml.ST_LineSpacingRuleAuto) prop.SetAlignment(wml.ST_JcLeft) run := p.AddRun() runProp := run.Properties() runProp.SetSize(measurement.Distance(15 * measurement.Point)) runProp.SetFontFamily("宋体") run.AddText(v) run.AddBreak() } filePath := fmt.Sprintf("%s.docx", fileName) if e := doc.SaveToFile(filePath); e != nil { err = fmt.Errorf("生成docx失败, Err: %s", e.Error()) return } result = filePath return } // 导出pdf if exportType == SpeechRecognitionExportTypePdf { pdf := gofpdf.New("P", "mm", "A4", "") pdf.AddPage() pdf.AddUTF8Font("SimHei", "", "static/SimHei.ttf") // 此处字体文件只能用本地的 pdf.SetFont("SimHei", "", 14) // 计算可用内容区域宽度 w, _ := pdf.GetPageSize() marginLeft := 10.0 marginRight := 10.0 availableWidth := w - marginLeft - marginRight for _, v := range exportPdfArr { pdf.MultiCell(availableWidth, 10, v, "", "L", false) pdf.MultiCell(availableWidth, 5, "", "", "L", false) // 单纯的换行 } filePath := fmt.Sprintf("%s.pdf", fileName) if e := pdf.OutputFileAndClose(filePath); e != nil { err = fmt.Errorf("生成pdf失败, Err: %s", e.Error()) return } result = filePath return } // 默认导出txt filePath := fmt.Sprintf("%s.txt", fileName) file, e := os.Create(filePath) if e != nil { err = fmt.Errorf("生成txt文件失败, err: %s", e.Error()) return } defer file.Close() // 写入txt writer := bufio.NewWriter(file) _, e = writer.WriteString(exportText) if e != nil { err = fmt.Errorf("写入txt文件失败, err: %s", e.Error()) return } if e = writer.Flush(); e != nil { err = fmt.Errorf("刷新txt缓存失败, err: %s", e.Error()) return } result = filePath return }