/** * Music Generation Resource * Common interface for music generation models * * Supported Models: * - elevenlabs/eleven_music * - minimax/music-2.0 * - minimax/music-1.5 * - google/lyria2 * * API Endpoints: * - POST /v2/generate/audio - Create generation * - GET /v2/generate/audio?generation_id=xxx - Get status/result */ import { type AIMLAPIClient } from '../client'; import { buildPath } from './_paths'; // ===== VERSION ===== const VERSION = 'v2' as const; // ===== COMMON INTERFACES ===== export interface MusicGenerationParams { /** Model ID for the music generation model */ model: string; /** Music prompt/description */ prompt: string; /** Optional lyrics for the song */ lyrics?: string; /** Optional audio settings */ audio_setting?: { /** Sampling rate: 16000, 24000, 32000, or 44100 Hz */ sample_rate?: 16000 | 24000 | 32000 | 44100; /** Bit rate: 32000, 64000, 128000, or 256000 */ bitrate?: 32000 | 64000 | 128000 | 256000; /** Format: "mp3", "wav", or "pcm" */ format?: 'mp3' | 'wav' | 'pcm'; }; /** Optional negative prompt for content to exclude */ negative_prompt?: string; /** Optional seed for deterministic generation */ seed?: number; /** Optional music length in milliseconds (for Eleven Music) */ music_length_ms?: number; } export interface MusicGenerationResponse { /** The ID of the generated audio */ id: string; /** Current status: "queued", "generating", "completed", "error" */ status: 'queued' | 'generating' | 'completed' | 'error'; /** Audio file info (available when completed) */ audio_file?: { /** The URL where the file can be downloaded from */ url: string; /** Content type of the audio file */ content_type?: string; /** File name of the audio */ file_name?: string; /** File size in bytes */ file_size?: number; }; /** Error info (available when failed) */ error?: { name: string; message: string; }; /** Additional details about the generation */ meta?: { usage?: { /** The number of credits consumed during generation */ credits_used: number; }; }; /** Extra information about the generation */ extra_info?: { music_duration?: number; music_sample_rate?: number; music_channel?: number; bitrate?: number; music_size?: number; }; /** Trace ID for debugging */ trace_id?: string; } export interface MusicStatusResponse { /** The ID of the generated audio */ id: string; /** Current status: "queued", "generating", "completed", "error" */ status: 'queued' | 'generating' | 'completed' | 'error'; /** Audio file info (available when completed) */ audio_file?: { /** The URL where the file can be downloaded from */ url: string; /** Content type of the audio file */ content_type?: string; /** File name of the audio */ file_name?: string; /** File size in bytes */ file_size?: number; }; /** Error info (available when failed) */ error?: { name: string; message: string; }; /** Additional details about the generation */ meta?: { usage?: { /** The number of credits consumed during generation */ credits_used: number; }; }; /** Extra information about the generation */ extra_info?: { music_duration?: number; music_sample_rate?: number; music_channel?: number; bitrate?: number; music_size?: number; }; /** Trace ID for debugging */ trace_id?: string; } export class Music { constructor(private readonly _client: AIMLAPIClient) {} // ===== COMMON INTERFACE METHODS ===== /** * Common music generation interface * Routes to appropriate model based on the model parameter * * @example * ```typescript * const result = await client.music.generateMusic({ * model: 'elevenlabs/eleven_music', * prompt: 'lo-fi pop hip-hop ambient music', * music_length_ms: 20000, * }); * ``` */ async generateMusic(params: MusicGenerationParams): Promise { // Build request body based on common parameters const body: Record = { model: params.model, prompt: params.prompt, }; // Add optional parameters if provided if (params.lyrics) body.lyrics = params.lyrics; if (params.audio_setting) body.audio_setting = params.audio_setting; if (params.negative_prompt) body.negative_prompt = params.negative_prompt; if (params.seed !== undefined) body.seed = params.seed; if (params.music_length_ms) body.music_length_ms = params.music_length_ms; return this._client.post(buildPath('/generate/audio', VERSION), { body }); } /** * Common music generation with polling interface * Routes to appropriate model based on the model parameter * * @example * ```typescript * const result = await client.music.createWithPolling({ * model: 'elevenlabs/eleven_music', * prompt: 'lo-fi pop hip-hop ambient music', * music_length_ms: 20000, * }, 5, 300); * ``` */ async createWithPolling( params: MusicGenerationParams, maxAttempts: number = 5, timeoutSeconds: number = 300 ): Promise { const intervalMs = (timeoutSeconds * 1000) / maxAttempts; // Start generation const generation = await this.generateMusic(params); const generationId = generation.id; // Poll for completion for (let attempt = 0; attempt < maxAttempts; attempt++) { const result = await this.getStatus(generationId); if (result.status === 'completed' || result.status === 'error') { return result as MusicGenerationResponse; } // Wait before next poll if (attempt < maxAttempts - 1) { await new Promise((resolve) => setTimeout(resolve, intervalMs)); } } throw new Error(`Music generation timed out after ${maxAttempts} attempts`); } /** * Common polling interface for music generation * Polls for completion using a generation ID * * @example * ```typescript * const generation = await client.music.generateMusic({ * model: 'elevenlabs/eleven_music', * prompt: 'lo-fi pop hip-hop ambient music', * music_length_ms: 20000, * }); * * const result = await client.music.polling(generation.id, 5, 300); * ``` */ async polling( generation_id: string, attempts: number = 5, interval: number = 300 ): Promise { // Poll for completion using the generation ID for (let attempt = 0; attempt < attempts; attempt++) { const result = await this.getStatus(generation_id); if (result.status === 'completed' || result.status === 'error') { return result; } // Wait before next poll (interval in seconds, convert to milliseconds) if (attempt < attempts - 1) { await new Promise((resolve) => setTimeout(resolve, interval * 1000)); } } throw new Error(`Music generation timed out after ${attempts} attempts`); } /** * Get music generation status and result * * @example * ```typescript * const result = await client.music.getStatus('gen_abc123'); * if (result.status === 'completed') { * console.log('Audio URL:', result.audio_file?.url); * } * ``` */ async getStatus(generation_id: string): Promise { return this._client.get(buildPath('/generate/audio', VERSION), { query: { generation_id } }); } }