package elevenlabs import ( "context" "encoding/json" "fmt" "net/http" ) const ( // DefaultVoiceDesignModel is the default model for voice design. DefaultVoiceDesignModel = "eleven_multilingual_ttv_v2" // DefaultGuidanceScale balances prompt adherence with audio quality. DefaultGuidanceScale = 5.0 // DefaultLoudness is the default volume level. DefaultLoudness = 0.5 ) // DesignVoice generates voice previews from a text description. // Returns typically 3 voice previews to choose from. func (c *Client) DesignVoice(ctx context.Context, req VoiceDesignRequest) (*VoiceDesignResponse, error) { if req.VoiceDescription == "" { return nil, fmt.Errorf("%w: voice description is required", ErrInvalidConfig) } if len(req.VoiceDescription) < 20 || len(req.VoiceDescription) > 1000 { return nil, fmt.Errorf("%w: voice description must be 20-1000 characters", ErrInvalidConfig) } // Set defaults if req.ModelID == "" { req.ModelID = DefaultVoiceDesignModel } if req.GuidanceScale == 0 { req.GuidanceScale = DefaultGuidanceScale } if req.Loudness == 0 { req.Loudness = DefaultLoudness } // If no text provided, enable auto-generation if req.Text == "" { req.AutoGenerateText = true } respBody, err := c.doRequest(ctx, http.MethodPost, "/text-to-voice/design", req) if err != nil { return nil, fmt.Errorf("design voice: %w", err) } var resp VoiceDesignResponse if err := json.Unmarshal(respBody, &resp); err != nil { return nil, fmt.Errorf("unmarshal voice design response: %w", err) } return &resp, nil } // SaveDesignedVoice saves a voice preview as a permanent voice. // The GeneratedVoiceID comes from a VoicePreview returned by DesignVoice. func (c *Client) SaveDesignedVoice(ctx context.Context, req SaveVoiceRequest) (*SaveVoiceResponse, error) { if req.VoiceName == "" { return nil, fmt.Errorf("%w: voice name is required", ErrInvalidConfig) } if req.GeneratedVoiceID == "" { return nil, fmt.Errorf("%w: generated voice ID is required", ErrInvalidConfig) } respBody, err := c.doRequest(ctx, http.MethodPost, "/text-to-voice/create-voice-from-preview", req) if err != nil { return nil, fmt.Errorf("save designed voice: %w", err) } var resp SaveVoiceResponse if err := json.Unmarshal(respBody, &resp); err != nil { return nil, fmt.Errorf("unmarshal save voice response: %w", err) } return &resp, nil } // DeleteVoice removes a voice from the account. func (c *Client) DeleteVoice(ctx context.Context, voiceID string) error { if voiceID == "" { return fmt.Errorf("%w: voice ID is required", ErrInvalidConfig) } path := fmt.Sprintf("/voices/%s", voiceID) _, err := c.doRequest(ctx, http.MethodDelete, path, nil) if err != nil { return fmt.Errorf("delete voice: %w", err) } return nil }