@@ -7,7 +7,11 @@ import { ModelPartial } from "../types";
77import { SDKError } from "../../errors/base" ;
88import { ExitCode } from "../../errors/codes" ;
99import { toMerged } from "es-toolkit/object" ;
10- import { MUSIC_GENERATE_MODELS , musicGenerateModel } from "../../commands/music/models" ;
10+ import {
11+ MUSIC_COVER_MODELS ,
12+ MUSIC_GENERATE_MODELS ,
13+ musicGenerateModel ,
14+ } from "../../commands/music/models" ;
1115import { decodeAudioStream } from "../../utils/audio-stream" ;
1216
1317function hexToBuffer ( hex : string ) : Buffer {
@@ -189,32 +193,19 @@ export class MusicSDK extends Client {
189193 const {
190194 model, output_format, stream, prompt, lyrics, is_instrumental, lyrics_optimizer,
191195 } = normalized ;
192- if ( is_instrumental && lyrics ) {
193- throw new SDKError ( 'Cannot use is_instrumental with lyrics' , ExitCode . USAGE ) ;
194- }
195-
196- if ( lyrics_optimizer && ( lyrics || is_instrumental ) ) {
197- throw new SDKError ( 'Cannot use lyrics_optimizer with lyrics or is_instrumental' , ExitCode . USAGE ) ;
198- }
199-
200- if ( ! prompt && ! lyrics && ! is_instrumental && ! lyrics_optimizer ) {
201- throw new SDKError ( 'At least one of prompt or lyrics or is_instrumental or lyrics_optimizer is required' , ExitCode . USAGE ) ;
202- }
203-
204- if ( ( is_instrumental || lyrics_optimizer ) && ! prompt ?. trim ( ) ) {
205- throw new SDKError (
206- 'prompt is required with is_instrumental or lyrics_optimizer' ,
207- ExitCode . USAGE ,
208- ) ;
209- }
210-
211- if ( ! is_instrumental && ! lyrics_optimizer && ! lyrics ?. trim ( ) ) {
212- throw new SDKError ( 'lyrics is required' , ExitCode . USAGE ) ;
213- }
214-
215- if ( model && ! MUSIC_GENERATE_MODELS . includes ( model as typeof MUSIC_GENERATE_MODELS [ number ] ) ) {
196+ const effectiveModel = model ?? musicGenerateModel ( this . config ) ;
197+ const isGenerateModel = MUSIC_GENERATE_MODELS . includes (
198+ effectiveModel as typeof MUSIC_GENERATE_MODELS [ number ] ,
199+ ) ;
200+ const isCoverModel = MUSIC_COVER_MODELS . includes (
201+ effectiveModel as typeof MUSIC_COVER_MODELS [ number ] ,
202+ ) ;
203+ if ( ! isGenerateModel && ! isCoverModel ) {
216204 throw new SDKError (
217- `Invalid model: ${ model } . Valid models are ${ MUSIC_GENERATE_MODELS . join ( ', ' ) } .` ,
205+ `Invalid model: ${ effectiveModel } . Valid models are ${ [
206+ ...MUSIC_GENERATE_MODELS ,
207+ ...MUSIC_COVER_MODELS ,
208+ ] . join ( ', ' ) } .`,
218209 ExitCode . USAGE ,
219210 ) ;
220211 }
@@ -233,13 +224,102 @@ export class MusicSDK extends Client {
233224 ) ;
234225 }
235226
236- const targetPrompt = this . buildPrompt ( {
227+ let targetPrompt = this . buildPrompt ( {
237228 ...params ,
238229 is_instrumental,
239230 } ) ;
240231
232+ if ( isCoverModel ) {
233+ if ( is_instrumental ) {
234+ throw new SDKError (
235+ 'is_instrumental is only supported by music generation models' ,
236+ ExitCode . USAGE ,
237+ ) ;
238+ }
239+ if ( lyrics_optimizer ) {
240+ throw new SDKError (
241+ 'lyrics_optimizer is only supported by music generation models' ,
242+ ExitCode . USAGE ,
243+ ) ;
244+ }
245+ delete normalized . is_instrumental ;
246+ delete normalized . lyrics_optimizer ;
247+
248+ targetPrompt = targetPrompt ?. trim ( ) ;
249+ const coverPromptLength = targetPrompt ?. length ?? 0 ;
250+ if ( coverPromptLength < 10 || coverPromptLength > 300 ) {
251+ throw new SDKError (
252+ 'prompt must be between 10 and 300 characters for music cover models' ,
253+ ExitCode . USAGE ,
254+ ) ;
255+ }
256+
257+ const hasAudioUrl = Boolean ( normalized . audio_url ?. trim ( ) ) ;
258+ const hasAudioBase64 = Boolean ( normalized . audio_base64 ?. trim ( ) ) ;
259+ const hasCoverFeatureId = Boolean ( normalized . cover_feature_id ?. trim ( ) ) ;
260+ const sourceCount = [ hasAudioUrl , hasAudioBase64 , hasCoverFeatureId ]
261+ . filter ( Boolean ) . length ;
262+ if ( sourceCount !== 1 ) {
263+ throw new SDKError (
264+ 'Exactly one of audio_url, audio_base64, or cover_feature_id is required for music cover models' ,
265+ ExitCode . USAGE ,
266+ ) ;
267+ }
268+ if ( hasAudioUrl ) normalized . audio_url = normalized . audio_url ?. trim ( ) ;
269+ else delete normalized . audio_url ;
270+ if ( hasAudioBase64 ) normalized . audio_base64 = normalized . audio_base64 ?. trim ( ) ;
271+ else delete normalized . audio_base64 ;
272+ if ( hasCoverFeatureId ) {
273+ normalized . cover_feature_id = normalized . cover_feature_id ?. trim ( ) ;
274+ } else {
275+ delete normalized . cover_feature_id ;
276+ }
277+
278+ const coverLyrics = lyrics ?. trim ( ) ;
279+ const lyricsLength = coverLyrics ?. length ?? 0 ;
280+ if ( hasCoverFeatureId && lyricsLength === 0 ) {
281+ throw new SDKError (
282+ 'lyrics is required with cover_feature_id' ,
283+ ExitCode . USAGE ,
284+ ) ;
285+ }
286+ if ( coverLyrics ) normalized . lyrics = coverLyrics ;
287+ else delete normalized . lyrics ;
288+ if ( lyricsLength > 0 && ( lyricsLength < 10 || lyricsLength > 1000 ) ) {
289+ throw new SDKError (
290+ 'lyrics must be between 10 and 1000 characters for music cover models' ,
291+ ExitCode . USAGE ,
292+ ) ;
293+ }
294+ } else {
295+ if ( normalized . audio_url || normalized . audio_base64 || normalized . cover_feature_id ) {
296+ throw new SDKError (
297+ 'audio_url, audio_base64, and cover_feature_id are only supported by music cover models' ,
298+ ExitCode . USAGE ,
299+ ) ;
300+ }
301+ if ( is_instrumental && lyrics ) {
302+ throw new SDKError ( 'Cannot use is_instrumental with lyrics' , ExitCode . USAGE ) ;
303+ }
304+ if ( lyrics_optimizer && ( lyrics || is_instrumental ) ) {
305+ throw new SDKError ( 'Cannot use lyrics_optimizer with lyrics or is_instrumental' , ExitCode . USAGE ) ;
306+ }
307+ if ( ! prompt && ! lyrics && ! is_instrumental && ! lyrics_optimizer ) {
308+ throw new SDKError ( 'At least one of prompt or lyrics or is_instrumental or lyrics_optimizer is required' , ExitCode . USAGE ) ;
309+ }
310+ if ( ( is_instrumental || lyrics_optimizer ) && ! prompt ?. trim ( ) ) {
311+ throw new SDKError (
312+ 'prompt is required with is_instrumental or lyrics_optimizer' ,
313+ ExitCode . USAGE ,
314+ ) ;
315+ }
316+ if ( ! is_instrumental && ! lyrics_optimizer && ! lyrics ?. trim ( ) ) {
317+ throw new SDKError ( 'lyrics is required' , ExitCode . USAGE ) ;
318+ }
319+ }
320+
241321 return toMerged ( {
242- model : musicGenerateModel ( this . config ) ,
322+ model : effectiveModel ,
243323 audio_setting : {
244324 format : 'mp3' ,
245325 sample_rate : 44100 ,
0 commit comments