runapi-suno 0.2.4 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9b946388dec7aef3f7af7ff7d859b7f94dc119f836c2a5537d8875ea634be22b
4
- data.tar.gz: a8416da674406ec542569bb7f953a6f5bc2c09848e6cc45825707476192151a4
3
+ metadata.gz: 7408c126663eb2e648020669baa1dc31570c6df7eb74a2d38856c8ba25eb7d3e
4
+ data.tar.gz: 69968db8a1c4d03cafe72847d036be448f8eadb2edc7797445660371c700807a
5
5
  SHA512:
6
- metadata.gz: 9c92a126f53ab0471d08b2f99299b627ce0f9532e24c376e8110b21984ea7eb3866c414ca14ac4a72a79ceed283e91ae271c84461ef74200dc95c5a294392cf5
7
- data.tar.gz: 5959bfa9a1f62749536cfc9a0d0f6adcea7fdf656b9330814e0b8830acd853f82384758468ec126dcc8b275fd9966583f63a6beb11f21cc29f32fa4e4e19c204
6
+ metadata.gz: 3cfaaa5a15a681d6ce11f36c8c04d116a245191f2148da349d71b0429fc931421e315d9bfe81faebabde0dc077afe7779969fa1eccc728510d43c5f3dda280f6
7
+ data.tar.gz: 0c40c4d0cd2e6a45dc2c30614217b994caf48ce3e6871f3c8945e918bbae174f66b0fae6e3a11452f5dadcf48093f721e2045dca0c9014972395d8e3c34b652b
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # Suno AI API Ruby SDK for RunAPI
2
+
3
+ The suno ai api Ruby SDK is the language-specific package for Suno on RunAPI. Use this suno ai api package for song generation, lyrics, vocal, extension, and audio transformation flows when your application needs JSON request bodies, task status lookup, and consistent RunAPI errors in Ruby.
4
+
5
+ This suno ai api README is the Ruby package guide inside the public `suno-sdk` repository. For the repository overview, start at `../README.md`; for model details, use https://runapi.ai/models/suno; for API reference, use https://runapi.ai/docs#suno; for SDK docs, use https://runapi.ai/docs#sdk-suno.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ gem install runapi-suno
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```ruby
16
+ require "runapi-suno"
17
+
18
+ client = RunApi::Suno::Client.new
19
+ task = client.generations.create(
20
+ # Pass the Suno JSON request body from https://runapi.ai/docs#suno.
21
+ )
22
+ status = client.generations.get(task.id)
23
+ ```
24
+
25
+ Use `create` when you want to submit a task and return quickly, `get` when you need the latest task state, and `run` when a script should create and poll until completion. In web request handlers, prefer `create` plus webhook or later `get` polling so a worker is not held open.
26
+
27
+ RunAPI-generated file URLs are temporary. Download and store generated images, videos, audio, or other files in your own durable storage within 7 days; do not treat returned URLs as long-term assets.
28
+
29
+ ## Language notes
30
+
31
+ Use Ruby keyword arguments and the `RunApi::Suno` error classes when building music jobs, Rails workers, or scripts. The available resources include generations, extensions, upload and extensions, covers, upload and covers, instrumentals, vocals, vocal removals, midi, wav conversions, music videos, lyrics, timestamped lyrics, section replacements, mashups, sounds, personas, and styles. Keep `RUNAPI_API_KEY` in the environment or your secret manager; never commit API keys or callback secrets.
32
+
33
+ ## Links
34
+
35
+ - Model page: https://runapi.ai/models/suno
36
+ - SDK docs: https://runapi.ai/docs#sdk-suno
37
+ - Product docs: https://runapi.ai/docs#suno
38
+ - Pricing and rate limits: https://runapi.ai/models/suno/v4
39
+ - Provider comparison: https://runapi.ai/providers/suno
40
+ - Full catalog: https://runapi.ai/models
41
+ - Repository: https://github.com/runapi-ai/suno-sdk
42
+
43
+ ## License
44
+
45
+ Licensed under the Apache License, Version 2.0.
@@ -2,17 +2,61 @@
2
2
 
3
3
  module RunApi
4
4
  module Suno
5
- class Client
6
- attr_reader :text_to_music, :extend_music, :generate_artwork, :cover_audio,
7
- :add_instrumental, :add_vocals, :separate_audio_stems, :generate_midi,
8
- :convert_audio, :visualize_music, :generate_lyrics, :get_timestamped_lyrics,
9
- :replace_section, :create_mashup, :text_to_sound, :generate_persona, :boost_style
5
+ # Suno music platform client covering song generation, extension, covers, stems,
6
+ # MIDI, lyrics, mashups, sound effects, visualization, personas, and voice cloning.
7
+ #
8
+ # @example Generate a song from a text prompt
9
+ # client = RunApi::Suno::Client.new(api_key: "sk-your-api-key")
10
+ # result = client.text_to_music.run(
11
+ # prompt: "A chill lo-fi beat with soft vocals",
12
+ # model: "suno-v4.5-plus"
13
+ # )
14
+ class Client < RunApi::Core::Client
15
+ # @return [Resources::TextToMusic] generates songs from a text prompt with configurable vocal mode, style, and persona
16
+ attr_reader :text_to_music
17
+ # @return [Resources::ExtendMusic] continues an existing track from a specified timestamp
18
+ attr_reader :extend_music
19
+ # @return [Resources::GenerateArtwork] creates cover artwork for an existing music task
20
+ attr_reader :generate_artwork
21
+ # @return [Resources::CoverAudio] re-records vocals over an uploaded audio file with a new style or voice
22
+ attr_reader :cover_audio
23
+ # @return [Resources::AddInstrumental] generates and adds an instrumental backing track to uploaded audio
24
+ attr_reader :add_instrumental
25
+ # @return [Resources::AddVocals] generates and adds vocals to an uploaded instrumental track
26
+ attr_reader :add_vocals
27
+ # @return [Resources::SeparateAudioStems] splits a track into individual instrument stems
28
+ attr_reader :separate_audio_stems
29
+ # @return [Resources::GenerateMidi] extracts per-instrument MIDI note data from a generated track
30
+ attr_reader :generate_midi
31
+ # @return [Resources::ConvertAudio] converts a generated track to WAV format
32
+ attr_reader :convert_audio
33
+ # @return [Resources::VisualizeMusic] generates a music visualization video from an existing track
34
+ attr_reader :visualize_music
35
+ # @return [Resources::GenerateLyrics] produces AI-generated lyrics from a text prompt
36
+ attr_reader :generate_lyrics
37
+ # @return [Resources::GetTimestampedLyrics] retrieves word-level timing alignment for a track (synchronous)
38
+ attr_reader :get_timestamped_lyrics
39
+ # @return [Resources::ReplaceSection] re-generates a time range within an existing track
40
+ attr_reader :replace_section
41
+ # @return [Resources::CreateMashup] blends two audio tracks into a single new composition
42
+ attr_reader :create_mashup
43
+ # @return [Resources::TextToSound] generates sound effects from a text description
44
+ attr_reader :text_to_sound
45
+ # @return [Resources::VoiceToValidationPhrase] step 1 of voice cloning: extracts a validation phrase
46
+ attr_reader :voice_to_validation_phrase
47
+ # @return [Resources::RegenerateValidationPhrase] step 2 (optional) of voice cloning: requests a new phrase
48
+ attr_reader :regenerate_validation_phrase
49
+ # @return [Resources::GenerateVoice] step 3 of voice cloning: trains a custom voice
50
+ attr_reader :generate_voice
51
+ # @return [Resources::CheckVoice] step 4 of voice cloning: checks whether a custom voice is ready (synchronous)
52
+ attr_reader :check_voice
53
+ # @return [Resources::GeneratePersona] creates a reusable style or voice persona from a track's vocals (synchronous)
54
+ attr_reader :generate_persona
55
+ # @return [Resources::BoostStyle] generates style/genre tags from a text description (synchronous)
56
+ attr_reader :boost_style
10
57
 
11
58
  def initialize(api_key: nil, **options)
12
- @api_key = Core::Auth.resolve_api_key(api_key)
13
-
14
- client_options = Core::ClientOptions.new(api_key: @api_key, **options)
15
- http = client_options.http_client || Core::HttpClient.new(client_options)
59
+ super
16
60
 
17
61
  @text_to_music = Resources::TextToMusic.new(http)
18
62
  @extend_music = Resources::ExtendMusic.new(http)
@@ -29,6 +73,10 @@ module RunApi
29
73
  @replace_section = Resources::ReplaceSection.new(http)
30
74
  @create_mashup = Resources::CreateMashup.new(http)
31
75
  @text_to_sound = Resources::TextToSound.new(http)
76
+ @voice_to_validation_phrase = Resources::VoiceToValidationPhrase.new(http)
77
+ @regenerate_validation_phrase = Resources::RegenerateValidationPhrase.new(http)
78
+ @generate_voice = Resources::GenerateVoice.new(http)
79
+ @check_voice = Resources::CheckVoice.new(http)
32
80
  @generate_persona = Resources::GeneratePersona.new(http)
33
81
  @boost_style = Resources::BoostStyle.new(http)
34
82
  end
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Generates and adds an instrumental backing track to uploaded audio.
6
7
  class AddInstrumental
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Generates and adds vocals to an uploaded instrumental track.
6
7
  class AddVocals
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Generates style/genre tags from a text description for use in style fields. Synchronous (run only).
6
7
  class BoostStyle
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RunApi
4
+ module Suno
5
+ module Resources
6
+ # Step 4 of voice cloning: checks whether a custom voice is ready for use. Synchronous (run only).
7
+ class CheckVoice
8
+ include RunApi::Core::ResourceHelpers
9
+
10
+ ENDPOINT = "/api/v1/suno/check_voice"
11
+ RESPONSE_CLASS = Types::CheckVoiceResponse
12
+
13
+ def initialize(http)
14
+ @http = http
15
+ end
16
+
17
+ def run(**params)
18
+ params = compact_params(params)
19
+ validate_params!(params)
20
+ request(:post, ENDPOINT, body: params)
21
+ end
22
+
23
+ private
24
+
25
+ def validate_params!(params)
26
+ Validators.validate_check_voice!(params, self)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Converts a generated track to WAV format.
6
7
  class ConvertAudio
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Re-records vocals over an uploaded audio file with a new style or voice.
6
7
  class CoverAudio
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Blends two audio tracks into a single new composition.
6
7
  class CreateMashup
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Continues an existing track from a specified timestamp, inheriting or overriding its settings.
6
7
  class ExtendMusic
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Creates cover artwork for an existing music task.
6
7
  class GenerateArtwork
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Produces AI-generated lyrics from a text prompt.
6
7
  class GenerateLyrics
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Extracts per-instrument MIDI note data from a generated track.
6
7
  class GenerateMidi
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Creates a reusable style or voice persona from an existing track's vocals. Synchronous (run only).
6
7
  class GeneratePersona
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RunApi
4
+ module Suno
5
+ module Resources
6
+ # Step 3 of voice cloning: trains a custom voice from the user's recording of the validation phrase.
7
+ class GenerateVoice
8
+ include RunApi::Core::ResourceHelpers
9
+
10
+ ENDPOINT = "/api/v1/suno/generate_voice"
11
+ RESPONSE_CLASS = Types::VoiceGenerationResponse
12
+ COMPLETED_RESPONSE_CLASS = Types::CompletedVoiceGenerationResponse
13
+
14
+ def initialize(http)
15
+ @http = http
16
+ end
17
+
18
+ def run(**params)
19
+ task = create(**params)
20
+ poll_until_complete { get(task.id) }
21
+ end
22
+
23
+ def create(**params)
24
+ params = compact_params(params)
25
+ validate_params!(params)
26
+ request(:post, ENDPOINT, body: params)
27
+ end
28
+
29
+ def get(id)
30
+ request(:get, "#{ENDPOINT}/#{id}")
31
+ end
32
+
33
+ private
34
+
35
+ def validate_params!(params)
36
+ Validators.validate_generate_voice!(params, self)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Retrieves word-level timing alignment for a track. Synchronous (run only, no create/get polling).
6
7
  class GetTimestampedLyrics
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RunApi
4
+ module Suno
5
+ module Resources
6
+ # Step 2 (optional) of voice cloning: requests a new, easier validation phrase.
7
+ class RegenerateValidationPhrase
8
+ include RunApi::Core::ResourceHelpers
9
+
10
+ ENDPOINT = "/api/v1/suno/regenerate_validation_phrase"
11
+ RESPONSE_CLASS = Types::ValidationPhraseResponse
12
+ COMPLETED_RESPONSE_CLASS = Types::CompletedValidationPhraseResponse
13
+
14
+ def initialize(http)
15
+ @http = http
16
+ end
17
+
18
+ def run(**params)
19
+ task = create(**params)
20
+ poll_until_complete { get(task.id) }
21
+ end
22
+
23
+ def create(**params)
24
+ params = compact_params(params)
25
+ validate_params!(params)
26
+ request(:post, ENDPOINT, body: params)
27
+ end
28
+
29
+ def get(id)
30
+ request(:get, "#{ENDPOINT}/#{id}")
31
+ end
32
+
33
+ private
34
+
35
+ def validate_params!(params)
36
+ Validators.validate_regenerate_validation_phrase!(params, self)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Re-generates a time range within an existing track with new lyrics and style.
6
7
  class ReplaceSection
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Splits a track into individual instrument stems (vocals, drums, bass, guitar, etc.).
6
7
  class SeparateAudioStems
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Generates songs from a text prompt with configurable vocal mode, style, and persona.
6
7
  class TextToMusic
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Generates sound effects (not music) from a text description with optional looping and BPM control.
6
7
  class TextToSound
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -3,6 +3,7 @@
3
3
  module RunApi
4
4
  module Suno
5
5
  module Resources
6
+ # Generates a music visualization video from an existing track.
6
7
  class VisualizeMusic
7
8
  include RunApi::Core::ResourceHelpers
8
9
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RunApi
4
+ module Suno
5
+ module Resources
6
+ # Step 1 of voice cloning: extracts a validation phrase from a voice recording for the user to re-record.
7
+ class VoiceToValidationPhrase
8
+ include RunApi::Core::ResourceHelpers
9
+
10
+ ENDPOINT = "/api/v1/suno/voice_to_validation_phrase"
11
+ RESPONSE_CLASS = Types::ValidationPhraseResponse
12
+ COMPLETED_RESPONSE_CLASS = Types::CompletedValidationPhraseResponse
13
+
14
+ def initialize(http)
15
+ @http = http
16
+ end
17
+
18
+ def run(**params)
19
+ task = create(**params)
20
+ poll_until_complete { get(task.id) }
21
+ end
22
+
23
+ def create(**params)
24
+ params = compact_params(params)
25
+ validate_params!(params)
26
+ request(:post, ENDPOINT, body: params)
27
+ end
28
+
29
+ def get(id)
30
+ request(:get, "#{ENDPOINT}/#{id}")
31
+ end
32
+
33
+ private
34
+
35
+ def validate_params!(params)
36
+ Validators.validate_voice_to_validation_phrase!(params, self)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -2,18 +2,46 @@
2
2
 
3
3
  module RunApi
4
4
  module Suno
5
+ # Suno type definitions, response models, and enum constants.
5
6
  module Types
6
- MODELS = %w[suno-v5.5 suno-v5 suno-v4.5-plus suno-v4.5-all suno-v4.5 suno-v4 suno-v3.5].freeze
7
+ # Suno music generation engine versions. V5.5 has highest quality; V4 is the earliest available.
8
+ MODELS = %w[suno-v5.5 suno-v5 suno-v4.5-plus suno-v4.5-all suno-v4.5 suno-v4].freeze
9
+ # Model versions that support sound effect generation (subset of MODELS).
7
10
  SOUND_MODELS = %w[suno-v5 suno-v5.5].freeze
11
+ # Musical keys (major and minor) for sound effect generation.
8
12
  SOUND_KEYS = %w[
9
13
  Cm C#m Dm D#m Em Fm F#m Gm G#m Am A#m Bm
10
14
  C C# D D# E F F# G G# A A# B
11
15
  ].freeze
12
- VOCAL_GENDERS = %w[f m].freeze
13
- PERSONA_MODELS = %w[style_persona voice_persona].freeze
16
+ VOCAL_GENDERS = %w[female male].freeze
17
+ # "style" applies genre/mood without changing voice; "voice" applies cloned voice characteristics.
18
+ PERSONA_TYPES = %w[style voice].freeze
19
+ # "source" inherits settings from the original track; "custom" requires explicit values.
20
+ PARAMETER_MODES = %w[source custom].freeze
21
+ # auto_lyrics: generates from prompt; exact_lyrics: sings literal lyrics; instrumental: no vocals.
22
+ VOCAL_MODES = %w[auto_lyrics exact_lyrics instrumental].freeze
23
+ # separate_vocal: isolates vocals+instrumental; split_stem: splits into all individual instruments.
14
24
  SEPARATE_AUDIO_STEMS_TYPES = %w[separate_vocal split_stem].freeze
25
+ # Language for the voice-cloning validation phrase the user must read back.
26
+ VALIDATION_PHRASE_LANGUAGES = %w[en zh es fr pt de ja ko hi ru].freeze
27
+ # Singing ability of the voice being cloned; calibrates model expectations.
28
+ SINGER_SKILL_LEVELS = %w[beginner intermediate advanced professional].freeze
15
29
 
30
+ # Metadata and URLs for a generated music track.
16
31
  class Audio < RunApi::Core::BaseModel
32
+ optional :id, String
33
+ optional :audio_url, String
34
+ optional :stream_audio_url, String
35
+ optional :image_url, String
36
+ optional :lyrics, String
37
+ optional :model_name, String
38
+ optional :title, String
39
+ optional :tags, [String]
40
+ optional :duration, Numeric
41
+ end
42
+
43
+ # Metadata and URLs for a generated sound effect (distinct from music Audio).
44
+ class SoundAudio < RunApi::Core::BaseModel
17
45
  optional :id, String
18
46
  optional :audio_url, String
19
47
  optional :stream_audio_url, String
@@ -21,14 +49,16 @@ module RunApi
21
49
  optional :prompt, String
22
50
  optional :model_name, String
23
51
  optional :title, String
24
- optional :tags, [ String ]
52
+ optional :tags, [String]
25
53
  optional :duration, Numeric
26
54
  end
27
55
 
56
+ # A URL to a generated cover artwork image.
28
57
  class Cover < RunApi::Core::BaseModel
29
58
  required :url, String
30
59
  end
31
60
 
61
+ # Word-level timing alignment for a single word in a track.
32
62
  class AlignedWord < RunApi::Core::BaseModel
33
63
  required :word, String
34
64
  required :success
@@ -37,6 +67,7 @@ module RunApi
37
67
  required :palign, Numeric
38
68
  end
39
69
 
70
+ # URLs for each isolated instrument stem after separation. Only populated stems have URLs.
40
71
  class SeparatedAudio < RunApi::Core::BaseModel
41
72
  optional :vocal_url, String
42
73
  optional :instrumental_url, String
@@ -54,6 +85,7 @@ module RunApi
54
85
  optional :woodwinds_url, String
55
86
  end
56
87
 
88
+ # A single MIDI note event within an instrument track.
57
89
  class MidiNote < RunApi::Core::BaseModel
58
90
  required :pitch, Numeric
59
91
  required :start_time, Numeric
@@ -61,22 +93,26 @@ module RunApi
61
93
  required :velocity, Numeric
62
94
  end
63
95
 
96
+ # All notes for a single instrument extracted from a track.
64
97
  class MidiInstrument < RunApi::Core::BaseModel
65
98
  required :name, String
66
- optional :notes, [ -> { MidiNote } ]
99
+ optional :notes, [-> { MidiNote }]
67
100
  end
68
101
 
102
+ # A section of generated lyrics with an optional section title (e.g. "Chorus", "Verse 1").
69
103
  class Lyric < RunApi::Core::BaseModel
70
104
  optional :title, String
71
105
  required :text, String
72
106
  end
73
107
 
108
+ # A reusable style or voice persona, referenced by ID in generation params.
74
109
  class Persona < RunApi::Core::BaseModel
75
110
  required :id, String
76
111
  required :name, String
77
112
  required :description, String
78
113
  end
79
114
 
115
+ # Base response for all Suno async tasks, carrying lifecycle status and generation progress.
80
116
  class AsyncTaskResponse < RunApi::Core::TaskResponse
81
117
  required :id, String
82
118
  required :status, String, enum: -> { RunApi::Core::TaskResponse::Status::ALL }
@@ -84,99 +120,137 @@ module RunApi
84
120
  optional :error, String
85
121
  end
86
122
 
123
+ # Result of a text-to-music generation task.
87
124
  class TextToMusicResponse < AsyncTaskResponse
88
- optional :audios, [ -> { Audio } ]
125
+ optional :audios, [-> { Audio }]
89
126
  optional :audio_url, String
90
127
  end
91
128
 
129
+ # Result of a music extension task. +original_task_id+ references the source track.
92
130
  class ExtendMusicResponse < AsyncTaskResponse
93
- optional :audios, [ -> { Audio } ]
131
+ optional :audios, [-> { Audio }]
94
132
  optional :original_task_id, String
95
133
  end
96
134
 
135
+ # Result of an artwork generation task containing cover image URLs.
97
136
  class GenerateArtworkResponse < AsyncTaskResponse
98
- optional :covers, [ -> { Cover } ]
137
+ optional :covers, [-> { Cover }]
99
138
  end
100
139
 
140
+ # Result of a cover audio task.
101
141
  class CoverAudioResponse < AsyncTaskResponse
102
- optional :audios, [ -> { Audio } ]
142
+ optional :audios, [-> { Audio }]
103
143
  end
104
144
 
145
+ # Result of adding an instrumental backing track.
105
146
  class AddInstrumentalResponse < TextToMusicResponse; end
147
+ # Result of adding vocals to a track.
106
148
  class AddVocalsResponse < TextToMusicResponse; end
107
- class TextToSoundResponse < TextToMusicResponse; end
108
149
 
150
+ # Result of a sound effect generation task (uses SoundAudio instead of Audio).
151
+ class TextToSoundResponse < AsyncTaskResponse
152
+ optional :audios, [-> { SoundAudio }]
153
+ end
154
+
155
+ # Result of a stem separation task.
109
156
  class SeparateAudioStemsResponse < AsyncTaskResponse
110
157
  optional :separated_audios, -> { SeparatedAudio }
111
158
  end
112
159
 
160
+ # Result of a MIDI extraction task with per-instrument note data.
113
161
  class GenerateMidiResponse < AsyncTaskResponse
114
- optional :instruments, [ -> { MidiInstrument } ]
162
+ optional :instruments, [-> { MidiInstrument }]
115
163
  end
116
164
 
165
+ # Result of a WAV conversion task.
117
166
  class ConvertAudioResponse < AsyncTaskResponse
118
167
  optional :wav_url, String
119
168
  optional :original_task_id, String
120
169
  end
121
170
 
171
+ # Result of a music visualization task containing the generated video URL.
122
172
  class VisualizeMusicResponse < AsyncTaskResponse
123
173
  optional :video_url, String
124
174
  optional :original_task_id, String
125
175
  end
126
176
 
177
+ # Result of a lyrics generation task with sectioned lyrics.
127
178
  class GenerateLyricsResponse < AsyncTaskResponse
128
- optional :lyrics, [ -> { Lyric } ]
179
+ optional :lyrics, [-> { Lyric }]
129
180
  end
130
181
 
182
+ # Synchronous response containing word-level timing data and waveform for a track.
131
183
  class GetTimestampedLyricsResponse < RunApi::Core::BaseModel
132
- optional :aligned_words, [ -> { AlignedWord } ]
133
- optional :waveform_data, [ Numeric ]
184
+ optional :aligned_words, [-> { AlignedWord }]
185
+ optional :waveform_data, [Numeric]
134
186
  optional :hoot_cer, Numeric
135
187
  optional :is_streamed
136
188
  end
137
189
 
190
+ # Result of a section replacement task.
138
191
  class ReplaceSectionResponse < AsyncTaskResponse
139
192
  optional :track, -> { Audio }
140
- optional :audios, [ -> { Audio } ]
193
+ optional :audios, [-> { Audio }]
141
194
  end
142
195
 
196
+ # Synchronous result of persona creation.
143
197
  class GeneratePersonaResponse < RunApi::Core::BaseModel
144
198
  required :persona, -> { Persona }
145
199
  optional :error, String
146
200
  end
147
201
 
202
+ # Synchronous result of style tag generation. +style+ contains the generated tags string.
148
203
  class BoostStyleResponse < RunApi::Core::BaseModel
149
204
  optional :style, String
150
205
  optional :error, String
151
206
  end
152
207
 
208
+ # Result of a mashup task.
153
209
  class CreateMashupResponse < AsyncTaskResponse
154
210
  optional :audio, -> { Audio }
155
- optional :audios, [ -> { Audio } ]
211
+ optional :audios, [-> { Audio }]
212
+ end
213
+
214
+ # Result of a voice-cloning validation phrase task. The user must re-record this phrase.
215
+ class ValidationPhraseResponse < AsyncTaskResponse
216
+ optional :provider_status, String
217
+ optional :validation_phrase, String
218
+ end
219
+
220
+ # Result of a voice generation (training) task. +voice_id+ is usable in subsequent generation params.
221
+ class VoiceGenerationResponse < AsyncTaskResponse
222
+ optional :provider_status, String
223
+ optional :voice_id, String
224
+ end
225
+
226
+ # Synchronous result indicating whether a custom voice is ready for use.
227
+ class CheckVoiceResponse < RunApi::Core::BaseModel
228
+ optional :is_available
229
+ optional :error, String
156
230
  end
157
231
 
158
232
  class CompletedTextToMusicResponse < TextToMusicResponse
159
- required :audios, [ -> { Audio } ]
233
+ required :audios, [-> { Audio }]
160
234
  end
161
235
 
162
236
  class CompletedExtendMusicResponse < ExtendMusicResponse
163
- required :audios, [ -> { Audio } ]
237
+ required :audios, [-> { Audio }]
164
238
  end
165
239
 
166
240
  class CompletedGenerateArtworkResponse < GenerateArtworkResponse
167
- required :covers, [ -> { Cover } ]
241
+ required :covers, [-> { Cover }]
168
242
  end
169
243
 
170
244
  class CompletedCoverAudioResponse < CoverAudioResponse
171
- required :audios, [ -> { Audio } ]
245
+ required :audios, [-> { Audio }]
172
246
  end
173
247
 
174
248
  class CompletedAddInstrumentalResponse < AddInstrumentalResponse
175
- required :audios, [ -> { Audio } ]
249
+ required :audios, [-> { Audio }]
176
250
  end
177
251
 
178
252
  class CompletedAddVocalsResponse < AddVocalsResponse
179
- required :audios, [ -> { Audio } ]
253
+ required :audios, [-> { Audio }]
180
254
  end
181
255
 
182
256
  class CompletedSeparateAudioStemsResponse < SeparateAudioStemsResponse
@@ -184,7 +258,7 @@ module RunApi
184
258
  end
185
259
 
186
260
  class CompletedGenerateMidiResponse < GenerateMidiResponse
187
- required :instruments, [ -> { MidiInstrument } ]
261
+ required :instruments, [-> { MidiInstrument }]
188
262
  end
189
263
 
190
264
  class CompletedConvertAudioResponse < ConvertAudioResponse
@@ -196,7 +270,7 @@ module RunApi
196
270
  end
197
271
 
198
272
  class CompletedGenerateLyricsResponse < GenerateLyricsResponse
199
- required :lyrics, [ -> { Lyric } ]
273
+ required :lyrics, [-> { Lyric }]
200
274
  end
201
275
 
202
276
  class CompletedReplaceSectionResponse < ReplaceSectionResponse
@@ -204,11 +278,19 @@ module RunApi
204
278
  end
205
279
 
206
280
  class CompletedCreateMashupResponse < CreateMashupResponse
207
- required :audios, [ -> { Audio } ]
281
+ required :audios, [-> { Audio }]
208
282
  end
209
283
 
210
284
  class CompletedTextToSoundResponse < TextToSoundResponse
211
- required :audios, [ -> { Audio } ]
285
+ required :audios, [-> { SoundAudio }]
286
+ end
287
+
288
+ class CompletedValidationPhraseResponse < ValidationPhraseResponse
289
+ required :validation_phrase, String
290
+ end
291
+
292
+ class CompletedVoiceGenerationResponse < VoiceGenerationResponse
293
+ required :voice_id, String
212
294
  end
213
295
  end
214
296
  end
@@ -5,34 +5,34 @@ module RunApi
5
5
  module Validators
6
6
  module_function
7
7
 
8
+ MUSIC_PROMPT_SHAPE_ERROR = "choose a valid vocal_mode: auto_lyrics, exact_lyrics, or instrumental"
9
+
8
10
  def validate_text_to_music!(params, resource)
9
- if param(resource, params, :custom_mode)
10
- require_param!(resource, params, :style)
11
- require_param!(resource, params, :title)
12
- else
13
- require_param!(resource, params, :prompt)
14
- end
11
+ validate_music_prompt_shape!(params, resource)
15
12
  require_param!(resource, params, :model)
13
+ validate_optional!(resource, params, :vocal_mode, Types::VOCAL_MODES)
16
14
  validate_optional!(resource, params, :model, Types::MODELS)
17
15
  validate_optional!(resource, params, :vocal_gender, Types::VOCAL_GENDERS)
18
- validate_optional!(resource, params, :persona_model, Types::PERSONA_MODELS)
16
+ validate_optional!(resource, params, :persona_type, Types::PERSONA_TYPES)
19
17
  end
20
18
 
21
19
  def validate_extend_music!(params, resource)
22
20
  unless %i[task_id audio_id audio_url upload_url].any? { |key| param(resource, params, key) }
23
21
  raise Core::ValidationError, "task_id, audio_id, audio_url, or upload_url is required"
24
22
  end
25
- require_param!(resource, params, :default_param_flag)
23
+ require_param!(resource, params, :parameter_mode)
26
24
  require_param!(resource, params, :model)
27
25
 
28
- if truthy?(param(resource, params, :default_param_flag))
26
+ validate_optional!(resource, params, :parameter_mode, Types::PARAMETER_MODES)
27
+ if param(resource, params, :parameter_mode) == "custom"
29
28
  require_param!(resource, params, :style)
30
29
  require_param!(resource, params, :title)
31
30
  require_param!(resource, params, :continue_at)
32
31
  end
32
+ validate_extend_music_prompt_shape!(params, resource)
33
33
  validate_optional!(resource, params, :model, Types::MODELS)
34
34
  validate_optional!(resource, params, :vocal_gender, Types::VOCAL_GENDERS)
35
- validate_optional!(resource, params, :persona_model, Types::PERSONA_MODELS)
35
+ validate_optional!(resource, params, :persona_type, Types::PERSONA_TYPES)
36
36
  end
37
37
 
38
38
  def validate_generate_artwork!(params, resource)
@@ -42,15 +42,11 @@ module RunApi
42
42
  def validate_cover_audio!(params, resource)
43
43
  require_param!(resource, params, :upload_url)
44
44
  require_param!(resource, params, :model)
45
- if param(resource, params, :custom_mode)
46
- require_param!(resource, params, :style)
47
- require_param!(resource, params, :title)
48
- else
49
- require_param!(resource, params, :prompt)
50
- end
45
+ validate_music_prompt_shape!(params, resource)
46
+ validate_optional!(resource, params, :vocal_mode, Types::VOCAL_MODES)
51
47
  validate_optional!(resource, params, :model, Types::MODELS)
52
48
  validate_optional!(resource, params, :vocal_gender, Types::VOCAL_GENDERS)
53
- validate_optional!(resource, params, :persona_model, Types::PERSONA_MODELS)
49
+ validate_optional!(resource, params, :persona_type, Types::PERSONA_TYPES)
54
50
  end
55
51
 
56
52
  def validate_add_instrumental!(params, resource)
@@ -60,7 +56,7 @@ module RunApi
60
56
  end
61
57
 
62
58
  def validate_add_vocals!(params, resource)
63
- require_all!(resource, params, :upload_url, :prompt, :title, :negative_tags, :style, :model)
59
+ require_all!(resource, params, :upload_url, :lyrics, :title, :negative_tags, :style, :model)
64
60
  validate_optional!(resource, params, :model, Types::MODELS)
65
61
  validate_optional!(resource, params, :vocal_gender, Types::VOCAL_GENDERS)
66
62
  end
@@ -91,7 +87,7 @@ module RunApi
91
87
  end
92
88
 
93
89
  def validate_replace_section!(params, resource)
94
- require_all!(resource, params, :task_id, :audio_id, :prompt, :tags, :title, :infill_start_time, :infill_end_time)
90
+ require_all!(resource, params, :task_id, :audio_id, :lyrics, :tags, :title, :infill_start_time, :infill_end_time)
95
91
  if param(resource, params, :infill_end_time).to_f <= param(resource, params, :infill_start_time).to_f
96
92
  raise Core::ValidationError, "infill_end_time must be greater than infill_start_time"
97
93
  end
@@ -103,14 +99,11 @@ module RunApi
103
99
  raise Core::ValidationError, "upload_url_list must contain exactly 2 URLs"
104
100
  end
105
101
  require_param!(resource, params, :model)
106
- if param(resource, params, :custom_mode)
107
- require_all!(resource, params, :style, :title)
108
- require_param!(resource, params, :prompt) unless truthy?(param(resource, params, :instrumental))
109
- else
110
- require_param!(resource, params, :prompt)
111
- end
102
+ validate_music_prompt_shape!(params, resource)
103
+ validate_optional!(resource, params, :vocal_mode, Types::VOCAL_MODES)
112
104
  validate_optional!(resource, params, :model, Types::MODELS)
113
105
  validate_optional!(resource, params, :vocal_gender, Types::VOCAL_GENDERS)
106
+ validate_optional!(resource, params, :persona_type, Types::PERSONA_TYPES)
114
107
  end
115
108
 
116
109
  def validate_text_to_sound!(params, resource)
@@ -123,6 +116,30 @@ module RunApi
123
116
  end
124
117
  end
125
118
 
119
+ def validate_voice_to_validation_phrase!(params, resource)
120
+ require_all!(resource, params, :voice_url, :vocal_start_seconds, :vocal_end_seconds)
121
+ validate_optional!(resource, params, :language, Types::VALIDATION_PHRASE_LANGUAGES)
122
+
123
+ start_seconds = param(resource, params, :vocal_start_seconds).to_i
124
+ end_seconds = param(resource, params, :vocal_end_seconds).to_i
125
+ return if end_seconds > start_seconds
126
+
127
+ raise Core::ValidationError, "vocal_end_seconds must be greater than vocal_start_seconds"
128
+ end
129
+
130
+ def validate_regenerate_validation_phrase!(params, resource)
131
+ require_param!(resource, params, :task_id)
132
+ end
133
+
134
+ def validate_generate_voice!(params, resource)
135
+ require_all!(resource, params, :task_id, :verify_url)
136
+ validate_optional!(resource, params, :singer_skill_level, Types::SINGER_SKILL_LEVELS)
137
+ end
138
+
139
+ def validate_check_voice!(params, resource)
140
+ require_param!(resource, params, :task_id)
141
+ end
142
+
126
143
  def validate_generate_persona!(params, resource)
127
144
  require_all!(resource, params, :task_id, :audio_id, :name, :description)
128
145
  end
@@ -131,6 +148,45 @@ module RunApi
131
148
  require_param!(resource, params, :description)
132
149
  end
133
150
 
151
+ def validate_music_prompt_shape!(params, resource)
152
+ mode = param(resource, params, :vocal_mode).to_s
153
+ has_prompt = truthy_presence?(param(resource, params, :prompt))
154
+ has_lyrics = truthy_presence?(param(resource, params, :lyrics))
155
+ has_style = truthy_presence?(param(resource, params, :style))
156
+ has_title = truthy_presence?(param(resource, params, :title))
157
+
158
+ valid_shape = case mode
159
+ when "auto_lyrics"
160
+ has_prompt && !has_lyrics && !has_style && !has_title
161
+ when "exact_lyrics"
162
+ !has_prompt && has_lyrics && has_style && has_title
163
+ when "instrumental"
164
+ !has_prompt && !has_lyrics && has_style && has_title
165
+ else
166
+ false
167
+ end
168
+ return if valid_shape
169
+
170
+ raise Core::ValidationError, MUSIC_PROMPT_SHAPE_ERROR
171
+ end
172
+
173
+ def validate_extend_music_prompt_shape!(params, resource)
174
+ return unless truthy_presence?(param(resource, params, :lyrics))
175
+
176
+ if truthy_presence?(param(resource, params, :prompt))
177
+ raise Core::ValidationError, "prompt cannot be combined with lyrics"
178
+ end
179
+
180
+ if truthy?(param(resource, params, :instrumental))
181
+ raise Core::ValidationError, "lyrics cannot be used when instrumental is true"
182
+ end
183
+
184
+ upload_mode = %i[audio_url upload_url].any? { |key| truthy_presence?(param(resource, params, key)) }
185
+ return if param(resource, params, :parameter_mode) == "custom" && upload_mode
186
+
187
+ raise Core::ValidationError, "lyrics can only be used when extending uploaded audio with custom parameters"
188
+ end
189
+
134
190
  def require_all!(resource, params, *keys)
135
191
  keys.each { |key| require_param!(resource, params, key) }
136
192
  end
@@ -148,7 +204,13 @@ module RunApi
148
204
  end
149
205
 
150
206
  def truthy?(value)
151
- [ true, 1, "1", "true", "TRUE", "True" ].include?(value)
207
+ [true, 1, "1", "true", "TRUE", "True"].include?(value)
208
+ end
209
+
210
+ def truthy_presence?(value)
211
+ return !value.empty? if value.respond_to?(:empty?)
212
+
213
+ !value.nil?
152
214
  end
153
215
  end
154
216
  end
data/lib/runapi/suno.rb CHANGED
@@ -18,6 +18,10 @@ require_relative "suno/resources/get_timestamped_lyrics"
18
18
  require_relative "suno/resources/replace_section"
19
19
  require_relative "suno/resources/create_mashup"
20
20
  require_relative "suno/resources/text_to_sound"
21
+ require_relative "suno/resources/voice_to_validation_phrase"
22
+ require_relative "suno/resources/regenerate_validation_phrase"
23
+ require_relative "suno/resources/generate_voice"
24
+ require_relative "suno/resources/check_voice"
21
25
  require_relative "suno/resources/generate_persona"
22
26
  require_relative "suno/resources/boost_style"
23
27
  require_relative "suno/client"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: runapi-suno
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - RunAPI
@@ -15,28 +15,34 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.2.4
18
+ version: 0.2.6
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 0.2.4
26
- description: RunAPI Suno SDK for JavaScript, Ruby, and Go
25
+ version: 0.2.6
26
+ description: The suno ai api Ruby SDK is the language-specific package for Suno on
27
+ RunAPI. Use this suno ai api package for song generation, lyrics, vocal, extension,
28
+ and audio transformation flows when your application needs JSON request bodies,
29
+ task status lookup, and consistent RunAPI errors in Ruby.
27
30
  email:
28
31
  - contact@runapi.ai
29
32
  executables: []
30
33
  extensions: []
31
- extra_rdoc_files: []
34
+ extra_rdoc_files:
35
+ - README.md
32
36
  files:
33
37
  - LICENSE
38
+ - README.md
34
39
  - lib/runapi-suno.rb
35
40
  - lib/runapi/suno.rb
36
41
  - lib/runapi/suno/client.rb
37
42
  - lib/runapi/suno/resources/add_instrumental.rb
38
43
  - lib/runapi/suno/resources/add_vocals.rb
39
44
  - lib/runapi/suno/resources/boost_style.rb
45
+ - lib/runapi/suno/resources/check_voice.rb
40
46
  - lib/runapi/suno/resources/convert_audio.rb
41
47
  - lib/runapi/suno/resources/cover_audio.rb
42
48
  - lib/runapi/suno/resources/create_mashup.rb
@@ -45,12 +51,15 @@ files:
45
51
  - lib/runapi/suno/resources/generate_lyrics.rb
46
52
  - lib/runapi/suno/resources/generate_midi.rb
47
53
  - lib/runapi/suno/resources/generate_persona.rb
54
+ - lib/runapi/suno/resources/generate_voice.rb
48
55
  - lib/runapi/suno/resources/get_timestamped_lyrics.rb
56
+ - lib/runapi/suno/resources/regenerate_validation_phrase.rb
49
57
  - lib/runapi/suno/resources/replace_section.rb
50
58
  - lib/runapi/suno/resources/separate_audio_stems.rb
51
59
  - lib/runapi/suno/resources/text_to_music.rb
52
60
  - lib/runapi/suno/resources/text_to_sound.rb
53
61
  - lib/runapi/suno/resources/visualize_music.rb
62
+ - lib/runapi/suno/resources/voice_to_validation_phrase.rb
54
63
  - lib/runapi/suno/types.rb
55
64
  - lib/runapi/suno/validators.rb
56
65
  homepage: https://runapi.ai/models/suno
@@ -58,7 +67,7 @@ licenses:
58
67
  - Apache-2.0
59
68
  metadata:
60
69
  homepage_uri: https://runapi.ai/models/suno
61
- documentation_uri: https://github.com/runapi-ai/suno-sdk/blob/main/README.md
70
+ documentation_uri: https://github.com/runapi-ai/suno-sdk/blob/main/ruby/README.md
62
71
  source_code_uri: https://github.com/runapi-ai/suno-sdk
63
72
  changelog_uri: https://github.com/runapi-ai/suno-sdk/blob/main/CHANGELOG.md
64
73
  rdoc_options: []
@@ -77,5 +86,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
77
86
  requirements: []
78
87
  rubygems_version: 4.0.10
79
88
  specification_version: 4
80
- summary: Suno API SDKs for JavaScript, Ruby, and Go on RunAPI.
89
+ summary: Suno AI API Ruby SDK for RunAPI
81
90
  test_files: []