### Install Python SDK Source: https://platform.sonilo.com/docs/sdks Install the official Sonilo Python client via pip. ```bash pip install sonilo ``` -------------------------------- ### Install Video Kit Companion Source: https://platform.sonilo.com/docs/sdks Install the video kit companion for local soundtrack mixing with ffmpeg. ```bash npm install sonilo sonilo-video-kit ``` -------------------------------- ### Install CLI Source: https://platform.sonilo.com/docs/sdks Install the Sonilo CLI tool using either Node or Python package managers. ```bash npm install -g sonilo-cli # Node (or: npx sonilo-cli account) pip install sonilo-cli # Python ``` -------------------------------- ### Install TypeScript SDK Source: https://platform.sonilo.com/docs/sdks Install the official Sonilo TypeScript client via npm. ```bash npm install sonilo ``` -------------------------------- ### Install Python Video Kit Companion Source: https://platform.sonilo.com/docs/sdks Install the Python video kit companion for local soundtrack mixing with ffmpeg. ```bash pip install sonilo sonilo-video-kit ``` -------------------------------- ### CLI Quickstart Source: https://platform.sonilo.com/docs/sdks Common commands for interacting with the Sonilo API via the terminal. ```bash # Plan limits, available services, and free-trial quota sonilo account # Usage summary (last 7 days) sonilo usage --days 7 # Music from a text prompt sonilo text-to-music --prompt "warm lo-fi piano, rain in the background" --duration 30 # Score a video with music (WAV output) sonilo video-to-music --video clip.mp4 --prompt "tense, driving synths" --format wav # Sound effects from a prompt sonilo text-to-sfx --prompt "glass shattering on concrete" --duration 3 # Poll an async task to completion sonilo tasks wait ``` -------------------------------- ### Retrieve Task Request Examples Source: https://platform.sonilo.com/docs/api/get-task Examples for fetching task status using cURL, Python, and JavaScript. ```bash curl "https://api.sonilo.com/v1/tasks/9f5f2f7e-..." \ -H "Authorization: Bearer sk_your_api_key" ``` ```python import requests resp = requests.get( "https://api.sonilo.com/v1/tasks/9f5f2f7e-...", headers={"Authorization": "Bearer sk_your_api_key"}, ) resp.raise_for_status() task = resp.json() print(task["status"]) ``` ```javascript const resp = await fetch( "https://api.sonilo.com/v1/tasks/9f5f2f7e-...", { headers: { Authorization: "Bearer sk_your_api_key" } }, ); if (!resp.ok) { throw new Error(`HTTP ${resp.status}: ${await resp.text()}`); } const task = await resp.json(); console.log(task.status); ``` -------------------------------- ### List Services Response Example Source: https://platform.sonilo.com/docs/api/list-services Example JSON response body returned by the List Services endpoint. ```json { "available_services": ["video_to_music", "text_to_music"], "rpm_limit": 60, "concurrency_limit": 4, "discount_factor": 1.0, "max_upload_size_mb": 300, "trial": { "video_to_music": { "granted": 1, "used": 0, "remaining": 1 }, "text_to_music": { "granted": 2, "used": 1, "remaining": 1 } } } ``` -------------------------------- ### Authenticate API Requests Source: https://platform.sonilo.com/docs/errors Example of providing the API key via the Authorization header. ```bash curl https://api.sonilo.com/v1/account/services \ -H "Authorization: Bearer sk_your_api_key" ``` -------------------------------- ### GET /v1/account/services Source: https://platform.sonilo.com/docs List available services and your account's live limits. ```APIDOC ## GET /v1/account/services ### Description List available services and your account's live limits. ### Method GET ### Endpoint /v1/account/services ``` -------------------------------- ### Quickstart Python SDK Source: https://platform.sonilo.com/docs/sdks Initialize the client and generate music from a text prompt. Requires the SONILO_API_KEY environment variable to be set. ```python from sonilo import Sonilo client = Sonilo() # reads SONILO_API_KEY track = client.text_to_music.generate( prompt="cinematic orchestral score", duration=60, ) track.save("output.mp3") ``` -------------------------------- ### Quickstart TypeScript SDK Source: https://platform.sonilo.com/docs/sdks Initialize the client and generate music from a text prompt. Requires the SONILO_API_KEY environment variable to be set. ```typescript import { SoniloClient } from "sonilo"; const sonilo = new SoniloClient(); // reads SONILO_API_KEY const track = await sonilo.textToMusic.generate({ prompt: "cinematic orchestral score", duration: 60, }); // track.audio is a Uint8Array of MP3 bytes ``` -------------------------------- ### Generate Music with Segmented Prompts Source: https://platform.sonilo.com/docs/api/text-to-music Examples for providing specific musical segments with timestamps and labels. ```bash curl -N -X POST https://api.sonilo.com/v1/text-to-music \ -H "Authorization: Bearer sk_your_api_key" \ -F "prompt=cinematic orchestral score" \ -F "duration=60" \ -F 'segments=[{"start": 0, "label": "intro", "prompt": "soft solo piano"}, {"start": 20, "label": "chorus", "prompt": "full orchestra, soaring strings"}, {"start": 45, "label": "outro", "prompt": "strings fade to silence"}]' ``` ```python import json import requests segments = [ {"start": 0, "label": "intro", "prompt": "soft solo piano"}, {"start": 20, "label": "chorus", "prompt": "full orchestra, soaring strings"}, {"start": 45, "label": "outro", "prompt": "strings fade to silence"}, ] with requests.post( "https://api.sonilo.com/v1/text-to-music", headers={"Authorization": "Bearer sk_your_api_key"}, files={ "prompt": (None, "cinematic orchestral score"), "duration": (None, "60"), "segments": (None, json.dumps(segments)), }, stream=True, timeout=300, ) as resp: resp.raise_for_status() for line in resp.iter_lines(decode_unicode=True): if not line: continue event = json.loads(line) print(event["type"], event) ``` ```javascript const segments = [ { start: 0, label: "intro", prompt: "soft solo piano" }, { start: 20, label: "chorus", prompt: "full orchestra, soaring strings" }, { start: 45, label: "outro", prompt: "strings fade to silence" }, ]; const form = new FormData(); form.append("prompt", "cinematic orchestral score"); form.append("duration", "60"); form.append("segments", JSON.stringify(segments)); const resp = await fetch("https://api.sonilo.com/v1/text-to-music", { method: "POST", headers: { Authorization: "Bearer sk_your_api_key", }, body: form, }); if (!resp.ok) { throw new Error(`HTTP ${resp.status}: ${await resp.text()}`); } const reader = resp.body.getReader(); const decoder = new TextDecoder(); let buf = ""; while (true) { const { value, done } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); let nl; while ((nl = buf.indexOf("\n")) !== -1) { const line = buf.slice(0, nl); buf = buf.slice(nl + 1); if (!line) continue; console.log(JSON.parse(line)); } } ``` -------------------------------- ### Generate Music with Basic Prompt Source: https://platform.sonilo.com/docs/api/text-to-music Examples for initiating a music generation request using a simple text prompt. ```bash curl -N -X POST https://api.sonilo.com/v1/text-to-music \ -H "Authorization: Bearer sk_your_api_key" \ -F "prompt=lofi hiphop beat" \ -F "duration=60" ``` ```python import json import requests with requests.post( "https://api.sonilo.com/v1/text-to-music", headers={"Authorization": "Bearer sk_your_api_key"}, files={ "prompt": (None, "lofi hiphop beat"), "duration": (None, "60"), }, stream=True, timeout=300, ) as resp: resp.raise_for_status() for line in resp.iter_lines(decode_unicode=True): if not line: continue event = json.loads(line) print(event["type"], event) ``` ```javascript const form = new FormData(); form.append("prompt", "lofi hiphop beat"); form.append("duration", "60"); const resp = await fetch("https://api.sonilo.com/v1/text-to-music", { method: "POST", headers: { Authorization: "Bearer sk_your_api_key", }, body: form, }); if (!resp.ok) { throw new Error(`HTTP ${resp.status}: ${await resp.text()}`); } const reader = resp.body.getReader(); const decoder = new TextDecoder(); let buf = ""; while (true) { const { value, done } = await reader.read(); if (done) break; buf += decoder.decode(value, { stream: true }); let nl; while ((nl = buf.indexOf("\n")) !== -1) { const line = buf.slice(0, nl); buf = buf.slice(nl + 1); if (!line) continue; console.log(JSON.parse(line)); } } ``` -------------------------------- ### GET /v1/account/usage Source: https://platform.sonilo.com/docs/api Get account usage totals and daily breakdowns. ```APIDOC ## GET /v1/account/usage ### Description Get account usage totals and daily breakdowns. ### Method GET ### Endpoint /v1/account/usage ``` -------------------------------- ### Retrieve API Usage Source: https://platform.sonilo.com/docs/api/get-usage Examples for fetching usage data using cURL, Python, and JavaScript. ```bash curl "https://api.sonilo.com/v1/account/usage?days=30" \ -H "Authorization: Bearer sk_your_api_key" ``` ```python import requests resp = requests.get( "https://api.sonilo.com/v1/account/usage", headers={"Authorization": "Bearer sk_your_api_key"}, params={"days": 30}, ) resp.raise_for_status() print(resp.json()) ``` ```javascript const url = new URL("https://api.sonilo.com/v1/account/usage"); url.searchParams.set("days", "30"); const resp = await fetch(url, { headers: { Authorization: "Bearer sk_your_api_key" }, }); console.log(await resp.json()); ``` -------------------------------- ### GET /v1/account/usage Source: https://platform.sonilo.com/docs Retrieve credit usage for your account. ```APIDOC ## GET /v1/account/usage ### Description Retrieve credit usage for your account. ### Method GET ### Endpoint /v1/account/usage ``` -------------------------------- ### GET /v1/account/services Source: https://platform.sonilo.com/docs/api List enabled services, limits, and upload caps for the account. ```APIDOC ## GET /v1/account/services ### Description List enabled services, limits, and upload caps for the account. ### Method GET ### Endpoint /v1/account/services ``` -------------------------------- ### GET /v1/tasks/{task_id} Source: https://platform.sonilo.com/docs/api Retrieve async task status and output URLs for SFX and audio-ducking jobs. ```APIDOC ## GET /v1/tasks/{task_id} ### Description Retrieve async task status and output URLs for SFX and audio-ducking jobs. ### Method GET ### Endpoint /v1/tasks/{task_id} ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier for the task. ``` -------------------------------- ### Task Status Response Source: https://platform.sonilo.com/docs/api/dubbing Example JSON response returned when a dubbing task is successfully initiated. ```json { "task_id": "9f5f2f7e-…", "status": "processing" } ``` -------------------------------- ### Generate and poll for sound effects Source: https://platform.sonilo.com/docs/api/text-to-sfx Examples for initiating a sound effect generation task and polling for the result using various languages. ```bash curl -X POST https://api.sonilo.com/v1/text-to-sfx \ -H "Authorization: Bearer sk_your_api_key" \ -F "prompt=heavy rain on a tin roof with distant thunder" \ -F "duration=10" # => {"task_id": "9f5f2f7e-...", "status": "processing"} curl https://api.sonilo.com/v1/tasks/9f5f2f7e-... \ -H "Authorization: Bearer sk_your_api_key" # poll until "status" is "succeeded" or "failed" ``` ```python import time import requests headers = {"Authorization": "Bearer sk_your_api_key"} submit = requests.post( "https://api.sonilo.com/v1/text-to-sfx", headers=headers, files={ "prompt": (None, "heavy rain on a tin roof with distant thunder"), "duration": (None, "10"), }, timeout=30, ) submit.raise_for_status() task_id = submit.json()["task_id"] while True: poll = requests.get( f"https://api.sonilo.com/v1/tasks/{task_id}", headers=headers, timeout=30, ) poll.raise_for_status() task = poll.json() if task["status"] != "processing": break time.sleep(3) if task["status"] == "succeeded": print(task["audio"]["url"]) else: print(task["error"]) ``` ```javascript const headers = { Authorization: "Bearer sk_your_api_key" }; const form = new FormData(); form.append("prompt", "heavy rain on a tin roof with distant thunder"); form.append("duration", "10"); const submit = await fetch("https://api.sonilo.com/v1/text-to-sfx", { method: "POST", headers, body: form, }); if (!submit.ok) { throw new Error(`HTTP ${submit.status}: ${await submit.text()}`); } const { task_id } = await submit.json(); let task; do { await new Promise((r) => setTimeout(r, 3000)); const poll = await fetch(`https://api.sonilo.com/v1/tasks/${task_id}`, { headers }); if (!poll.ok) { throw new Error(`HTTP ${poll.status}: ${await poll.text()}`); } task = await poll.json(); } while (task.status === "processing"); if (task.status === "succeeded") { console.log(task.audio.url); } else { console.log(task.error); } ``` -------------------------------- ### GET /v1/tasks/{task_id} Source: https://platform.sonilo.com/docs Retrieve async task status and result URLs for music, SFX, combined-sound, and audio-ducking jobs. ```APIDOC ## GET /v1/tasks/{task_id} ### Description Retrieve async task status and result URLs for music, SFX, combined-sound, and audio-ducking jobs. ### Method GET ### Endpoint /v1/tasks/{task_id} ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier for the async task. ``` -------------------------------- ### GET /v1/account/services Source: https://platform.sonilo.com/docs Retrieves account services information for the authenticated user. ```APIDOC ## GET /v1/account/services ### Description Retrieves account services information for the authenticated user. ### Method GET ### Endpoint https://api.sonilo.com/v1/account/services ### Request Example curl https://api.sonilo.com/v1/account/services \ -H "Authorization: Bearer sk_your_api_key_here" ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/text-to-music Polls the status of an asynchronous music generation task. ```APIDOC ## GET /v1/tasks/:task_id ### Description Retrieves the status and results of a previously submitted generation task. ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier returned by the POST request. ### Response #### Success Response (200) - **status** (string) - The current status of the task ('processing', 'succeeded', or 'failed'). - **audio** (array) - Optional - List of generated audio streams if status is 'succeeded'. - **error** (string) - Optional - Error message if status is 'failed'. ``` -------------------------------- ### Generate Soundtrack with Prompts Source: https://platform.sonilo.com/docs/api/video-to-sound Submit a video URL along with music and sound effect prompts to generate a soundtrack. ```bash curl -X POST https://api.sonilo.com/v1/video-to-sound \ -H "Authorization: Bearer sk_your_api_key" \ -F "video_url=https://example.com/clip.mp4" \ -F "music_prompt=uplifting orchestral score" \ -F "sfx_prompt=match the on-screen action" # => {"task_id": "9f5f2f7e-...", "status": "processing"} curl https://api.sonilo.com/v1/tasks/9f5f2f7e-... \ -H "Authorization: Bearer sk_your_api_key" # poll until "status" is "succeeded" or "failed" ``` ```python import time import requests headers = {"Authorization": "Bearer sk_your_api_key"} submit = requests.post( "https://api.sonilo.com/v1/video-to-sound", headers=headers, files={ "video_url": (None, "https://example.com/clip.mp4"), "music_prompt": (None, "uplifting orchestral score"), "sfx_prompt": (None, "match the on-screen action"), }, timeout=30, ) submit.raise_for_status() task_id = submit.json()["task_id"] while True: poll = requests.get( f"https://api.sonilo.com/v1/tasks/{task_id}", headers=headers, timeout=30, ) poll.raise_for_status() task = poll.json() if task["status"] != "processing": break time.sleep(3) if task["status"] == "succeeded": print(task["output_url"]) else: print(task["error"]) ``` ```javascript const headers = { Authorization: "Bearer sk_your_api_key" }; const form = new FormData(); form.append("video_url", "https://example.com/clip.mp4"); form.append("music_prompt", "uplifting orchestral score"); form.append("sfx_prompt", "match the on-screen action"); const submit = await fetch("https://api.sonilo.com/v1/video-to-sound", { method: "POST", headers, body: form, }); if (!submit.ok) { throw new Error(`HTTP ${submit.status}: ${await submit.text()}`); } const { task_id } = await submit.json(); let task; do { await new Promise((r) => setTimeout(r, 3000)); const poll = await fetch(`https://api.sonilo.com/v1/tasks/${task_id}`, { headers }); if (!poll.ok) { throw new Error(`HTTP ${poll.status}: ${await poll.text()}`); } task = await poll.json(); } while (task.status === "processing"); if (task.status === "succeeded") { console.log(task.output_url); } else { console.log(task.error); } ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/video-to-sound Polls the status of a previously submitted video-to-sound task. ```APIDOC ## GET /v1/tasks/:task_id ### Description Retrieves the status and result of a generation task. Poll this endpoint until the status is no longer 'processing'. ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The ID returned from the POST request. ### Response #### Success Response (200) - **task_id** (string) - The task identifier. - **status** (string) - The current status (e.g., "processing", "succeeded", "failed"). - **output_url** (string) - The URL to the generated audio file (if succeeded). - **error** (string) - Error message (if failed). ``` -------------------------------- ### Generate Video Soundtrack with Prompts Source: https://platform.sonilo.com/docs/api/video-to-video-sound Initiate a video sound generation task and poll for the result using basic prompts. ```bash curl -X POST https://api.sonilo.com/v1/video-to-video-sound \ -H "Authorization: Bearer sk_your_api_key" \ -F "video_url=https://example.com/clip.mp4" \ -F "music_prompt=uplifting orchestral score" \ -F "sfx_prompt=match the on-screen action" # => {"task_id": "9f5f2f7e-...", "status": "processing"} curl https://api.sonilo.com/v1/tasks/9f5f2f7e-... \ -H "Authorization: Bearer sk_your_api_key" # poll until "status" is "succeeded" or "failed" ``` ```python import time import requests headers = {"Authorization": "Bearer sk_your_api_key"} submit = requests.post( "https://api.sonilo.com/v1/video-to-video-sound", headers=headers, files={ "video_url": (None, "https://example.com/clip.mp4"), "music_prompt": (None, "uplifting orchestral score"), "sfx_prompt": (None, "match the on-screen action"), }, timeout=30, ) submit.raise_for_status() task_id = submit.json()["task_id"] while True: poll = requests.get( f"https://api.sonilo.com/v1/tasks/{task_id}", headers=headers, timeout=30, ) poll.raise_for_status() task = poll.json() if task["status"] != "processing": break time.sleep(3) if task["status"] == "succeeded": print(task["output_url"]) else: print(task["error"]) ``` ```javascript const headers = { Authorization: "Bearer sk_your_api_key" }; const form = new FormData(); form.append("video_url", "https://example.com/clip.mp4"); form.append("music_prompt", "uplifting orchestral score"); form.append("sfx_prompt", "match the on-screen action"); const submit = await fetch("https://api.sonilo.com/v1/video-to-video-sound", { method: "POST", headers, body: form, }); if (!submit.ok) { throw new Error(`HTTP ${submit.status}: ${await submit.text()}`); } const { task_id } = await submit.json(); let task; do { await new Promise((r) => setTimeout(r, 3000)); const poll = await fetch(`https://api.sonilo.com/v1/tasks/${task_id}`, { headers }); if (!poll.ok) { throw new Error(`HTTP ${poll.status}: ${await poll.text()}`); } task = await poll.json(); } while (task.status === "processing"); if (task.status === "succeeded") { console.log(task.output_url); } else { console.log(task.error); } ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/text-to-music Polls the status and result of an asynchronous music generation task. ```APIDOC ## GET /v1/tasks/:task_id ### Description Retrieves the status and result of a previously initiated asynchronous generation task. ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier returned by the initial POST request. ``` -------------------------------- ### Generate Music Asynchronously with Python Source: https://platform.sonilo.com/docs/api/text-to-music Use the requests library to submit a prompt and poll the task endpoint until completion. ```python import time import requests headers = {"Authorization": "Bearer sk_your_api_key"} submit = requests.post( "https://api.sonilo.com/v1/text-to-music", headers=headers, files={ "prompt": (None, "lofi hiphop beat"), "duration": (None, "60"), "mode": (None, "async"), }, timeout=30, ) submit.raise_for_status() task_id = submit.json()["task_id"] while True: task = requests.get( f"https://api.sonilo.com/v1/tasks/{task_id}", headers=headers, timeout=30, ).json() if task["status"] != "processing": break time.sleep(3) if task["status"] == "succeeded": for stream in task["audio"]: print(stream["stream_index"], stream["url"]) else: print(task["error"]) ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/audio-ducking Polls the status of a previously submitted audio ducking task. ```APIDOC ## GET /v1/tasks/:task_id ### Description Retrieves the current status and result of an audio ducking task using the task ID returned from the initial POST request. ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier for the task. ### Response #### Success Response (200) - **status** (string) - The current status of the task (e.g., "processing", "succeeded", "failed"). - **output_url** (string) - The URL to the processed audio file (present if status is "succeeded"). - **error** (string) - Error message (present if status is "failed"). ``` -------------------------------- ### POST /v1/text-to-sfx Source: https://platform.sonilo.com/docs Generate a sound effect from a prompt and poll the returned task. ```APIDOC ## POST /v1/text-to-sfx ### Description Generate a sound effect from a prompt and poll the returned task. ### Method POST ### Endpoint /v1/text-to-sfx ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/video-to-video-music Retrieves the status and result of a previously submitted generation task. ```APIDOC ## GET /v1/tasks/:task_id ### Description Poll this endpoint to check the status of a generation task until it reaches a terminal state. ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier returned from the POST request. ### Response #### Success Response (200) - **task_id** (string) - The task identifier. - **status** (string) - The current status (e.g., processing, succeeded, failed). ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/video-to-video-music Polls the status of a previously submitted video generation task. ```APIDOC ## GET /v1/tasks/:task_id ### Description Retrieves the status and result of a specific task. Poll this endpoint until the status is no longer "processing". ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier returned by the POST request. ### Response #### Success Response (200) - **status** (string) - The current status of the task (e.g., "succeeded", "failed", "processing"). - **video** (object) - Contains the result URL if the status is "succeeded". - **error** (string) - Error message if the status is "failed". ``` -------------------------------- ### Generate Music with Python Source: https://platform.sonilo.com/docs/quickstart A complete Python script to request music generation, handle 429 rate limits, parse the stream, and save the resulting audio file. ```python import base64 import json import os import sys import time from pathlib import Path import requests API_URL = "https://api.sonilo.com/v1/text-to-music" OUTPUT_FILE = Path("output.m4a") PROMPT = "30 seconds of upbeat electronic instrumental background music for a product launch video, no vocals." def retry_after_seconds(resp, attempt): value = resp.headers.get("Retry-After") if value: try: return max(1, int(value)) except ValueError: return 5 return min(2 ** attempt, 30) def open_generation(api_key): headers = { "Authorization": f"Bearer {api_key}", "User-Agent": "SoniloDocsSmokeTest/1.0 (+https://platform.sonilo.com/docs)", } files = { "prompt": (None, PROMPT), "duration": (None, "30"), } for attempt in range(1, 6): resp = requests.post(API_URL, headers=headers, files=files, stream=True, timeout=300) if resp.status_code != 429: return resp delay = retry_after_seconds(resp, attempt) resp.close() print(f"Rate limited. Retrying after {delay}s...", file=sys.stderr) time.sleep(delay) raise RuntimeError("rate_limit_exceeded: still receiving 429 after retries") def fail_for_http(resp): if resp.ok: return body = resp.text code = f"http_{resp.status_code}" message = body try: payload = resp.json() code = payload.get("code", code) message = payload.get("message", body) except ValueError: pass if resp.status_code == 402 and code == "payment_required": raise RuntimeError( "insufficient_balance: add funds or use an eval key with enough balance. " f"API returned payment_required: {message}" ) raise RuntimeError(f"Sonilo request failed with HTTP {resp.status_code}: {message}") def main(): api_key = os.environ.get("SONILO_API_KEY") if not api_key: raise RuntimeError("Set SONILO_API_KEY before running this script") chunks = [] complete = False with open_generation(api_key) as resp: fail_for_http(resp) for line in resp.iter_lines(decode_unicode=True): if not line: continue event = json.loads(line) if event.get("type") == "audio_chunk": chunks.append(base64.b64decode(event["data"])) elif event.get("type") == "complete": complete = True break elif event.get("type") == "error": code = event.get("code", "unknown_error") message = event.get("message", "Sonilo generation failed") raise RuntimeError(f"{code}: {message}") if not complete: raise RuntimeError("stream_incomplete: no complete event received") if not chunks: raise RuntimeError("empty_audio: complete event arrived without audio_chunk data") OUTPUT_FILE.write_bytes(b"".join(chunks)) print(f"Saved {OUTPUT_FILE} ({OUTPUT_FILE.stat().st_size} bytes)") if __name__ == "__main__": try: main() except Exception as exc: print(f"Error: {exc}", file=sys.stderr) sys.exit(1) ``` -------------------------------- ### Task Status Response Source: https://platform.sonilo.com/docs/api/audio-ducking Example of the JSON response returned when checking the status of a task. ```json { "task_id": "3f9c1a2e-...", "status": "processing" } ``` -------------------------------- ### POST /v1/text-to-sfx Source: https://platform.sonilo.com/docs/api Generate a sound effect from a prompt and duration. ```APIDOC ## POST /v1/text-to-sfx ### Description Generate a sound effect from a prompt and duration. ### Method POST ### Endpoint /v1/text-to-sfx ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/video-to-video-sound Polls the status of a previously submitted video-to-video sound generation task. ```APIDOC ## GET /v1/tasks/:task_id ### Description Retrieves the status and result of a specific task. Poll this endpoint until the status is no longer "processing". ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The ID returned from the initial POST request. ### Response #### Success Response (200) - **task_id** (string) - The task identifier. - **status** (string) - The current status (e.g., "succeeded", "failed", "processing"). - **output_url** (string) - URL to the generated video file (if succeeded). - **error** (string) - Error message (if failed). ``` -------------------------------- ### POST /v1/text-to-music Source: https://platform.sonilo.com/docs/api/text-to-music Submits a new music generation task based on a text prompt. ```APIDOC ## POST /v1/text-to-music ### Description Submits a request to generate music from a text prompt. The request is processed asynchronously. ### Method POST ### Endpoint https://api.sonilo.com/v1/text-to-music ### Request Body - **prompt** (string) - Required - The text description of the music to generate. - **duration** (string) - Required - The duration of the audio in seconds. - **mode** (string) - Required - The processing mode (e.g., "async"). ### Response #### Success Response (200) - **task_id** (string) - The unique identifier for the generated task. #### Response Example { "task_id": "9f5f2f7e-...", "status": "processing" } ``` -------------------------------- ### POST /v1/video-to-video-music Source: https://platform.sonilo.com/docs/api/video-to-video-music Initiates a video-to-video music generation task. Returns a task ID for status tracking. ```APIDOC ## POST /v1/video-to-video-music ### Description Generates a music-scored version of a video. This is an asynchronous operation that returns a task ID. ### Method POST ### Endpoint https://api.sonilo.com/v1/video-to-video-music ### Request Body - **video_url** (string) - Required - The URL of the source video. - **prompt** (string) - Optional - A description of the desired music style. - **preserve_speech** (boolean) - Optional - Whether to preserve original speech in the video. ### Response #### Success Response (202) - **task_id** (string) - The unique identifier for the processing task. - **status** (string) - The current status of the task (e.g., "processing"). ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/audio-ducking Poll the status of an audio ducking task until it reaches a terminal state. ```APIDOC ## GET /v1/tasks/:task_id ### Description Retrieves the status and result of a previously submitted audio ducking task. Poll this endpoint until the status is either "succeeded" or "failed". ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier returned by the POST /v1/audio-ducking request. ### Response #### Success Response (200) - **status** (string) - The current status of the task. - **output_url** (string) - The URL to the processed audio file (present if status is "succeeded"). - **error** (string) - Error message (present if status is "failed"). ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs/api/video-to-sfx Polls the status of a previously submitted sound effect generation task. ```APIDOC ## GET /v1/tasks/:task_id ### Description Retrieves the status and result of a sound effect generation task. Poll this endpoint until the status reaches a terminal state such as "succeeded" or "failed". ### Method GET ### Endpoint https://api.sonilo.com/v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier returned by the POST /v1/video-to-sfx request. ### Response #### Success Response (200) - **task_id** (string) - The task identifier. - **status** (string) - The current status (e.g., "processing", "succeeded", "failed"). - **audio** (object) - Optional - Contains the URL to the generated audio file if the status is "succeeded". - **error** (string) - Optional - Error message if the status is "failed". ``` -------------------------------- ### POST /v1/generate Source: https://platform.sonilo.com/docs/api/text-to-music Generates music based on a provided text prompt and configuration parameters. ```APIDOC ## POST /v1/generate ### Description Generates a music track based on a text prompt. Supports streaming or asynchronous processing. ### Method POST ### Endpoint /v1/generate ### Parameters #### Request Body - **prompt** (string) - Required - Text prompt describing the music to generate. Max length 2000 characters. - **duration** (integer) - Required - Desired duration of the output track in seconds. Min 5, max 360. - **mode** (string) - Optional - 'stream' (default) returns streaming NDJSON. 'async' returns 202 Accepted with a task_id. - **output_format** (string) - Optional - 'm4a' (default) or 'wav'. Requires mode=async. - **segments** (string) - Optional - JSON array of timed segment prompts for style changes. ``` -------------------------------- ### POST /v1/video-to-video-sfx Source: https://platform.sonilo.com/docs Add synchronized sound effects to a video and return a new video (async task). ```APIDOC ## POST /v1/video-to-video-sfx ### Description Add synchronized sound effects to a video and return a new video (async task). ### Method POST ### Endpoint /v1/video-to-video-sfx ``` -------------------------------- ### GET /v1/tasks/{task_id} Source: https://platform.sonilo.com/docs/api/get-task Retrieves the current status and output details for a specific task ID. ```APIDOC ## GET /v1/tasks/{task_id} ### Description Retrieves the status and results of an asynchronous task initiated by a generation request. ### Method GET ### Endpoint /v1/tasks/{task_id} ### Parameters #### Path Parameters - **task_id** (string) - Required - The task_id returned by the initial generation request. ### Response #### Success Response (200) - **task_id** (string) - The task identifier. - **type** (string) - The task type (e.g., video_to_sfx, text_to_sfx, audio_ducking, video_to_music, text_to_music). - **status** (string) - The current status: processing, succeeded, or failed. - **duration_seconds** (number) - The duration of the generated audio or video in seconds (present on success). - **audio** (object) - Generated audio details for SFX tasks. - **video** (object) - Generated video details for video-to-video tasks. - **output_url** (string) - Presigned download URL for audio-ducking or video-to-sound tasks. - **outputs** (object) - Map of language codes to download URLs for dubbing tasks. - **music** (object) - Raw generated music stem for video-to-sound tasks. - **sfx** (object) - Generated sound-effects stem for video-to-sound tasks. - **vocals** (object) - Isolated vocals stem for video-to-music tasks with preserve_speech. ``` -------------------------------- ### Define prompt template for text-to-music evals Source: https://platform.sonilo.com/docs/evals Provides a template for agents to generate runnable Python scripts for text-to-music tasks while adhering to specific API and file-capture requirements. ```text Using https://platform.sonilo.com/examples/text-to-music-output.py as the reference, create a runnable Python script that calls Sonilo text-to-music and saves output.m4a. Requirements: - Read SONILO_API_KEY from the environment. - Send a User-Agent. - Parse NDJSON audio_chunk events. - Wait for the complete event before writing output.m4a. - Respect Retry-After/backoff for 429. - Treat payment_required with Insufficient balance as insufficient_balance. - Do not create placeholder audio. - Verify output.m4a exists and file size is greater than 0 bytes. Codex/Sapient file-capture requirement: write every generated implementation file using an edit/patch mechanism that records the full file contents in the event stream, such as apply_patch or an equivalent file-edit tool. Do not create implementation files with shell redirection, cat heredocs, tee, printf >, npm init, npm install, scaffolding commands, or any command whose resulting file contents may not be captured. If generated_files is empty or contains placeholders like "[File created by Codex - content not captured in event stream]", this eval fails. Create directories if needed, then immediately patch real files with complete contents. Do not provide a final response or progress-only response until files exist and required verification has run. ``` -------------------------------- ### Task Response JSON Source: https://platform.sonilo.com/docs/api/get-task Example of the JSON response body returned by the task retrieval endpoint. ```json { "task_id": "9f5f2f7e-...", "type": "text_to_sfx", "status": "processing" } ``` -------------------------------- ### POST /v1/text-to-music Source: https://platform.sonilo.com/docs Generate music from a text prompt and a duration. ```APIDOC ## POST /v1/text-to-music ### Description Generate music from a text prompt and a duration. ### Method POST ### Endpoint /v1/text-to-music ``` -------------------------------- ### POST /v1/video-to-video-sound Source: https://platform.sonilo.com/docs/api/video-to-video-sound Initiates a video-to-video sound generation task. This endpoint accepts multipart/form-data and returns a task_id to track the progress of the generation. ```APIDOC ## POST /v1/video-to-video-sound ### Description Generates a combined soundtrack for a video, muxed with the original picture. Returns a task_id which can be used to poll for the final video file. ### Method POST ### Endpoint https://api.sonilo.com/v1/video-to-video-sound ### Request Body (multipart/form-data) - **video_url** (string) - Required - URL of the source video file. - **music_prompt** (string) - Optional - Description of the desired music. - **sfx_prompt** (string) - Optional - Description of the desired sound effects. - **preserve_speech** (boolean) - Optional - Whether to preserve original speech. - **ducking** (boolean) - Optional - Whether to apply audio ducking. - **segments** (string) - Optional - JSON string of segments with start, end, and prompt fields. ### Response #### Success Response (202) - **task_id** (string) - Unique identifier for the task. - **status** (string) - Current status of the task (e.g., "processing"). ``` -------------------------------- ### Generate Soundtrack with Segmented Prompts Source: https://platform.sonilo.com/docs/api/video-to-sound Submit a video with specific audio segments and configuration flags like speech preservation. ```bash curl -X POST https://api.sonilo.com/v1/video-to-sound \ -H "Authorization: Bearer sk_your_api_key" \ -F "video_url=https://example.com/clip.mp4" \ -F "preserve_speech=true" \ -F "ducking=false" \ -F 'segments=[{"start": 0, "end": 4, "prompt": "footsteps on gravel"}, {"start": 4, "end": 10, "prompt": "car door slam then engine starts"}]' ``` ```python import json import time import requests headers = {"Authorization": "Bearer sk_your_api_key"} segments = [ {"start": 0, "end": 4, "prompt": "footsteps on gravel"}, {"start": 4, "end": 10, "prompt": "car door slam then engine starts"}, ] submit = requests.post( "https://api.sonilo.com/v1/video-to-sound", headers=headers, files={ "video_url": (None, "https://example.com/clip.mp4"), "preserve_speech": (None, "true"), "ducking": (None, "false"), "segments": (None, json.dumps(segments)), }, timeout=30, ) submit.raise_for_status() task_id = submit.json()["task_id"] while True: poll = requests.get( f"https://api.sonilo.com/v1/tasks/{task_id}", headers=headers, timeout=30, ) poll.raise_for_status() task = poll.json() if task["status"] != "processing": break time.sleep(3) ``` ```javascript const segments = [ { start: 0, end: 4, prompt: "footsteps on gravel" }, { start: 4, end: 10, prompt: "car door slam then engine starts" }, ]; const form = new FormData(); form.append("video_url", "https://example.com/clip.mp4"); form.append("preserve_speech", "true"); form.append("ducking", "false"); form.append("segments", JSON.stringify(segments)); const submit = await fetch("https://api.sonilo.com/v1/video-to-sound", { method: "POST", headers: { Authorization: "Bearer sk_your_api_key" }, body: form, }); if (!submit.ok) { throw new Error(`HTTP ${submit.status}: ${await submit.text()}`); } const { task_id } = await submit.json(); ``` -------------------------------- ### GET /v1/tasks/:task_id Source: https://platform.sonilo.com/docs Polls the status of a generation task initiated by text-to-sfx, video-to-sfx, or audio-ducking endpoints. ```APIDOC ## GET /v1/tasks/:task_id ### Description Polls the status of a previously initiated generation task. ### Method GET ### Endpoint /v1/tasks/:task_id ### Parameters #### Path Parameters - **task_id** (string) - Required - The unique identifier for the generation task. ``` -------------------------------- ### POST /v1/audio-ducking Source: https://platform.sonilo.com/docs/api Mix voice or narration with background music, then poll the returned task. ```APIDOC ## POST /v1/audio-ducking ### Description Mix voice or narration with background music, then poll the returned task. ### Method POST ### Endpoint /v1/audio-ducking ```