package httpapi import ( "net/http" "github.com/easyai/easyai-ai-gateway/apps/api/internal/auth" ) // listClonedVoices godoc // @Summary 列出当前用户克隆音色 // @Description 返回当前用户在网关中维护的克隆音色,以及克隆时绑定的平台与平台模型。 // @Tags voice-clone // @Produce json // @Security BearerAuth // @Success 200 {object} map[string]any // @Failure 401 {object} ErrorEnvelope // @Failure 500 {object} ErrorEnvelope // @Router /api/v1/voice_clone/voices [get] // @Router /v1/voice_clone/voices [get] // @Router /voice_clone/voices [get] func (s *Server) listClonedVoices(w http.ResponseWriter, r *http.Request) { user, ok := auth.UserFromContext(r.Context()) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } if !apiKeyScopeAllowed(user, "voice.clone") { writeError(w, http.StatusForbidden, "api key scope does not allow this capability") return } items, err := s.store.ListClonedVoices(r.Context(), user) if err != nil { s.logger.Error("list cloned voices failed", "error", err) writeError(w, http.StatusInternalServerError, "list cloned voices failed") return } writeJSON(w, http.StatusOK, map[string]any{"items": items}) } // deleteClonedVoice godoc // @Summary 删除当前用户克隆音色 // @Description 先从上游供应商删除音色,成功后再将网关数据库中的音色记录标记为 deleted。 // @Tags voice-clone // @Produce json // @Security BearerAuth // @Param voiceID path string true "克隆音色记录 ID 或上游 voice_id" // @Success 200 {object} map[string]any // @Failure 400 {object} ErrorEnvelope // @Failure 401 {object} ErrorEnvelope // @Failure 403 {object} ErrorEnvelope // @Failure 404 {object} ErrorEnvelope // @Failure 502 {object} ErrorEnvelope // @Router /api/v1/voice_clone/voices/{voiceID} [delete] // @Router /v1/voice_clone/voices/{voiceID} [delete] // @Router /voice_clone/voices/{voiceID} [delete] func (s *Server) deleteClonedVoice(w http.ResponseWriter, r *http.Request) { user, ok := auth.UserFromContext(r.Context()) if !ok { writeError(w, http.StatusUnauthorized, "unauthorized") return } if !apiKeyScopeAllowed(user, "voice.clone") { writeError(w, http.StatusForbidden, "api key scope does not allow this capability") return } result, err := s.runner.DeleteClonedVoice(r.Context(), user, r.PathValue("voiceID")) if err != nil { writeErrorWithDetails(w, statusFromRunError(err), runErrorMessage(err), runErrorDetails(err), runErrorCode(err)) return } writeJSON(w, http.StatusOK, map[string]any{ "data": result.Voice, "upstream": result.Upstream, "requestId": result.RequestID, }) }