package service import ( "context" "encoding/base64" "ai-agent/digital-human/consts/public" "ai-agent/digital-human/dao" "ai-agent/digital-human/model/dto" "ai-agent/digital-human/model/entity" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/util/gconv" ) type customVoice struct{} // CustomVoice 自定义音色服务 var CustomVoice = new(customVoice) // CreateCustomVoice 创建自定义音色 func (s *customVoice) CreateCustomVoice(ctx context.Context, req *dto.CreateCustomVoiceReq) (res *dto.CreateCustomVoiceRes, err error) { g.Log().Infof(ctx, "创建自定义音色: name=%s, voiceType=%s", req.Name, req.VoiceType) // 插入数据库(状态:生成中) voiceID, err := dao.CustomVoice.Insert(ctx, req) if err != nil { return nil, err } switch req.VoiceType { case "design": // 设计音频:按模型约定只传 text + instruct taskID, err := TTS.CreateVoiceDesignTask(asyncCtx(ctx), req.Text, req.Description, "", 0) if err != nil { _, _ = dao.CustomVoice.UpdateStatus(ctx, voiceID, 2, "创建异步任务失败: "+err.Error(), "") return nil, err } _, _ = dao.AsyncTaskRef.Insert(ctx, &entity.AsyncTaskRef{ TaskID: taskID, State: 0, TableName: public.TableNameCustomVoice, BizID: voiceID, }) res = &dto.CreateCustomVoiceRes{VoiceID: gconv.String(voiceID)} g.Log().Infof(ctx, "自定义音色创建成功: voiceId=%d taskId=%s", voiceID, taskID) case "clone": // TODO : 克隆音色:使用语音转文字暂预留,后续找模型对应处理 refAudioBase64 := base64.StdEncoding.EncodeToString(req.ReferenceAudio) taskID, err := TTS.SpeechToText(asyncCtx(ctx), refAudioBase64) if err != nil { _, _ = dao.CustomVoice.UpdateStatus(ctx, voiceID, 2, "创建异步任务失败: "+err.Error(), "") return nil, err } _, _ = dao.AsyncTaskRef.Insert(ctx, &entity.AsyncTaskRef{ TaskID: taskID, State: 0, TableName: public.TableNameCustomVoice, BizID: voiceID, }) res = &dto.CreateCustomVoiceRes{VoiceID: gconv.String(voiceID)} g.Log().Infof(ctx, "克隆音色成功: voiceId=%d taskId=%s", voiceID, taskID) default: return nil, gerror.New("不支持的音色类型") } return } // ListCustomVoices 获取自定义音色列表 func (s *customVoice) ListCustomVoices(ctx context.Context, req *dto.ListCustomVoiceReq) (res *dto.ListCustomVoiceRes, err error) { customVoices, total, err := dao.CustomVoice.List(ctx, req) if err != nil { return nil, err } res = &dto.ListCustomVoiceRes{ Total: int64(total), List: make([]*dto.CustomVoiceItem, 0, len(customVoices)), } for _, cv := range customVoices { res.List = append(res.List, dao.CustomVoice.GetCustomVoiceItem(cv)) } return } // DeleteCustomVoice 删除自定义音色 func (s *customVoice) DeleteCustomVoice(ctx context.Context, req *dto.DeleteCustomVoiceReq) (err error) { // 验证音色是否存在 voiceID := gconv.Int64(req.VoiceID) _, err = dao.CustomVoice.GetOne(ctx, voiceID) if err != nil { return gerror.Wrapf(err, "音色不存在: %s", req.VoiceID) } // 删除音色 _, err = dao.CustomVoice.Delete(ctx, voiceID) if err != nil { return gerror.Wrapf(err, "删除音色失败: %s", req.VoiceID) } g.Log().Infof(ctx, "自定义音色删除成功: voiceId=%s", req.VoiceID) return nil }