package echomeet import ( "yunyan/comm" "yunyan/pb" "encoding/json" "fmt" "time" ) // @Summary 启动会议转写任务 // @Description 扣除积分并启动指定会议记录的转写/翻译任务,根据源语言自动路由到字节或阿里云 // @Tags Echomeet // @Accept json // @Produce json // @Security BearerAuth // @Param user body pb.EchomeetStartTaskReq true "请求数据" // @Success 200 {object} comm.HttpResult{data=pb.EchomeetStartTaskResp} "响应数据" // @Router /api/home/echomeet_starttask [post] func (this *apiComp) StartTask(session comm.IUserSession, req *pb.EchomeetStartTaskReq) (resp *pb.EchomeetStartTaskResp, errdata *pb.ErrorData) { var ( user *pb.DBUser model *pb.DBEchoMeetRecord err error ) user, err = this.module.model.getuser(session.GetUserId()) if err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Message: err.Error(), } return } model, err = this.module.model.getrecord(req.Id) if err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Message: err.Error(), } return } if model.State > pb.DBEchoMeetRecordState_Unknow && model.State < pb.DBEchoMeetRecordState_Completed { errdata = &pb.ErrorData{ Code: pb.ErrorCode_TaskStateError, Message: "任务状态错误", } return } if user.Meetintegral < int64(model.Seconds) { errdata = &pb.ErrorData{ Code: pb.ErrorCode_MeetIntegralNotEnough, Message: "积分不足", } return } user.Meetintegral -= int64(model.Seconds) err = this.module.model.updateuser(user) if err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_DBError, Message: err.Error(), } return } // 会议时长消耗埋点 if this.module.analyze != nil { this.module.analyze.Report(&comm.StatEvent{ Type: comm.StatEventMeeting, ProductId: user.Lastbindproductid, Uid: user.Uid, Second: int64(model.Seconds), }) } // 同步更新累计统计(排行榜依赖此表) if statistics, sErr := this.module.model.getStatistics(session.GetUserId()); sErr == nil { statistics.Meetnum += 1 statistics.Meettime += int64(model.Seconds) if uErr := this.module.model.updateStatistics(statistics); uErr != nil { this.module.Warnf("StartTask id:%d update userstatistics failed: %v", model.Id, uErr) } } // 写消费日志(供历史重建扫描) _ = this.module.model.addUseLog(&pb.DBUserUseLog{ Uid: session.GetUserId(), Logtype: pb.UserLogType_UserConsume, Ts: time.Now().Unix(), Addmeetsecond: -1 * int64(model.Seconds), }) tmpl, err := this.module.cache.ResolveTemplate(req.Tid, req.Templateid, req.Tolanguage) if err != nil { errdata = &pb.ErrorData{ Code: pb.ErrorCode_TemplateNotFound, Message: "模板不存在或不支持该语言", } this.module.Errorf("StartTask id:%d req:%+v 解析模板失败 err:%v", model.Id, req, err) return } model.State = pb.DBEchoMeetRecordState_AwaitTranscribing model.Starttime = time.Now().Unix() model.Processduration = 0 model.Templateid = tmpl.Id model.Isdistinguishspeaker = req.Isdistinguishspeaker model.Formlanguage = req.Formlanguage model.Tolanguage = req.Tolanguage // 选定识别服务:请求显式指定优先;否则按「后台配置的识别优先级 + 支持语言」自动选择 // (跳过不支持源语言的服务,修复西语被强路由到不支持西语的阿里的问题)。翻译在 TranslateProcess 内按优先级独立选择。 if req.ServiceType != pb.TranscribeService_TranscribeService_Auto && req.ServiceType != pb.TranscribeService_TranscribeService_Unknown { model.ServiceType = this.module.providers.ResolveServiceType(req.ServiceType, model.Formlanguage) } else { model.ServiceType = this.module.providers.selectASR(model.Formlanguage) } // 总结所用文本大模型:客户端选择优先,留空则用后台配置的默认(优先级最高的启用条目)。 model.SummaryModel = req.SummaryModel if model.SummaryModel == "" { model.SummaryModel = this.module.providers.DefaultSummaryId() } this.module.model.saverecord(model) this.module.Infof("StartTask id:%d uid:%s formlang:%s tolang:%s seconds:%d size:%d distinguishSpeaker:%v service:%s", model.Id, model.Uid, model.Formlanguage, model.Tolanguage, model.Seconds, model.Size, model.Isdistinguishspeaker, ServiceTypeName(model.ServiceType)) if model.Rtype == "VOICETRANSLAT" { this.module.Infof("StartTask id:%d → 语音翻译", model.Id) var contexts []*pb.ContextStruct if err = json.Unmarshal([]byte(model.Original), &contexts); err != nil { this.module.Errorf("Summary id:%d 解析 Original 失败 err:%v", model.Id, err) errdata = &pb.ErrorData{ Code: pb.ErrorCode_SystemError, Message: "json.Unmarshal Original 失败", } return } else { this.module.tasks.TranslateProcess(model, contexts) _ = this.module.tasks.SubmitAITask(model) } return } else { if model.Audiourl == "" { errdata = &pb.ErrorData{ Code: pb.ErrorCode_AudioUrlEmpty, Message: "音频URL为空", } return } this.module.Infof("StartTask id:%d → service:%s lang:%s", model.Id, ServiceTypeName(model.ServiceType), model.Formlanguage) switch model.ServiceType { case pb.TranscribeService_TranscribeService_ByteDance: if model.Seconds <= byteDanceFlashMaxSeconds && model.Size <= byteDanceFlashMaxBytes { _ = this.module.tasks.SubmitShortAudioTask(model) } else { _ = this.module.tasks.SubmitLongAudioTask(model) } case pb.TranscribeService_TranscribeService_Ali: _ = this.module.tasks.SubmitAliAudioTask(model) case pb.TranscribeService_TranscribeService_Microsoft, pb.TranscribeService_TranscribeService_Google: _ = this.module.tasks.SubmitTranscribeTask(model) default: errdata = &pb.ErrorData{ Code: pb.ErrorCode_SystemError, Message: fmt.Sprintf("unsupported service_type: %d", model.ServiceType), } return } } resp = &pb.EchomeetStartTaskResp{} return }