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.
 
 
 
 
 
 

174 lines
5.8 KiB

package echomeet
import (
"yunyan/comm"
"yunyan/pb"
"encoding/json"
"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,
ChannelId: user.Lastbindchannelid,
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
// 三段选路(后台编排,fail-closed:未配置直接报错提示去后台配置):
// - 识别/翻译:按后台优先级 + 语言支持过滤,客户端不可指定;
// - 总结:后台默认模型;开关允许时客户端可用 summary_svc_id 指定。
llmSvcId, _, err := this.module.providers.PickLLM(req.SummarySvcId)
if err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_SystemError, Message: err.Error()}
return
}
model.LlmSvcId = llmSvcId
// 翻译:源=目标语言时无需翻译,选路失败不阻断(后续改语言重译时再补选)。
if mtSvcId, _, merr := this.module.providers.PickMT(model.Formlanguage); merr == nil {
model.MtSvcId = mtSvcId
} else if model.Formlanguage != model.Tolanguage {
errdata = &pb.ErrorData{Code: pb.ErrorCode_SystemError, Message: merr.Error()}
return
}
if model.Rtype == "VOICETRANSLAT" {
// 语音翻译:已有转写文本,只走翻译+总结,无需识别选路。
this.module.model.saverecord(model)
this.module.Infof("StartTask id:%d → 语音翻译 mt:%s llm:%s", model.Id, model.MtSvcId, model.LlmSvcId)
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
}
if model.Audiourl == "" {
errdata = &pb.ErrorData{
Code: pb.ErrorCode_AudioUrlEmpty,
Message: "音频URL为空",
}
return
}
asrSvcId, _, _, err := this.module.providers.PickASR(model.Formlanguage)
if err != nil {
errdata = &pb.ErrorData{Code: pb.ErrorCode_SystemError, Message: err.Error()}
return
}
model.AsrSvcId = asrSvcId
this.module.model.saverecord(model)
this.module.Infof("StartTask id:%d uid:%s formlang:%s tolang:%s seconds:%d size:%d distinguishSpeaker:%v asr:%s mt:%s llm:%s",
model.Id, model.Uid, model.Formlanguage, model.Tolanguage, model.Seconds, model.Size, model.Isdistinguishspeaker,
model.AsrSvcId, model.MtSvcId, model.LlmSvcId)
// 字节短音频走专用限流队列(flash 同步通道);其余统一走通用异步提交。
if this.module.providers.ASRProvider(asrSvcId) == "bytedance" &&
model.Seconds <= byteDanceFlashMaxSeconds && model.Size <= byteDanceFlashMaxBytes {
_ = this.module.tasks.SubmitShortAudioTask(model)
} else {
_ = this.module.tasks.SubmitTranscribeTask(model)
}
resp = &pb.EchomeetStartTaskResp{}
return
}