### Python: Install Libraries Source: https://docs.modulate.ai/guides/code-examples Install the necessary Python libraries for synchronous (requests) and asynchronous (aiohttp) API interactions. ```bash # Synchronous pip install requests # Async pip install aiohttp ``` -------------------------------- ### Set up Python environment Source: https://docs.modulate.ai/quickstart Installs necessary Python dependencies for interacting with the Modulate API. Ensure you are in a virtual environment. ```bash mkdir modulate-quickstart && cd modulate-quickstart python3 -m venv .venv source .venv/bin/activate # macOS / Linux # .venv\Scripts\activate # Windows pip install -r requirements.txt ``` ```text requests>=2.31.0 requests-toolbelt>=1.0.0 websockets>=12.0 python-dotenv>=1.0.0 urllib3<2.0 ``` -------------------------------- ### Install Dependencies (Node.js) Source: https://docs.modulate.ai/guides/code-examples Installs necessary packages for Node.js API interactions, including WebSocket client, form data handling, and fetch utilities. ```bash npm install ws form-data node-fetch # or use built-in fetch (Node 18+) and the ws package for WebSocket ``` -------------------------------- ### Python: Concurrent Batch Processing with Semaphore Source: https://docs.modulate.ai/guides/code-examples This example demonstrates concurrent batch processing of multiple audio files using 'aiohttp' and 'asyncio'. It employs a semaphore to manage the number of simultaneous requests, respecting organizational limits. Errors during processing are reported. ```python import asyncio import glob import aiohttp URL = "https://modulate-developer-apis.com/api/velma-2-stt-batch-english-vfast" MAX_CONCURRENT = 5 # set to your organization's limit semaphore = asyncio.Semaphore(MAX_CONCURRENT) async def process_file(session: aiohttp.ClientSession, filepath: str) -> dict: async with semaphore: data = aiohttp.FormData() data.add_field( "upload_file", open(filepath, "rb"), filename=filepath.rsplit("/", 1)[-1], content_type="application/octet-stream", ) async with session.post(URL, data=data) as resp: if resp.status != 200: return {"file": filepath, "error": f"{resp.status}: {await resp.text()}"} result = await resp.json() return {"file": filepath, **result} async def main(): files = glob.glob("audio_files/*.opus") async with aiohttp.ClientSession(headers={"X-API-Key": "YOUR_API_KEY"}) as session: results = await asyncio.gather(*[process_file(session, f) for f in files]) for r in results: status = "OK" if "error" not in r else f"FAILED: {r['error']}" print(f"{r['file']}: {status}") asyncio.run(main()) ``` -------------------------------- ### cURL: SVD Batch - Minimal Example Source: https://docs.modulate.ai/guides/code-examples A minimal cURL example for Synthetic Voice Detection (SVD) batch processing. Ensure you replace YOUR_API_KEY and the audio file path. ```bash curl -X POST https://modulate-developer-apis.com/api/velma-2-synthetic-voice-detection-batch \ -H "X-API-Key: YOUR_API_KEY" \ -F "upload_file=@/path/to/audio.mp3" ``` -------------------------------- ### Testing WebSocket APIs with websocat Source: https://docs.modulate.ai/guides/code-examples Demonstrates how to install and use `websocat` for command-line testing of WebSocket APIs. Provides a basic connection test for the STT Streaming API. ```bash # Install car go install websocat # Basic connection test (STT Streaming) websocat "wss://modulate-developer-apis.com/api/velma-2-stt-streaming?api_key=YOUR_API_KEY&speaker_diarization=true" ``` -------------------------------- ### JavaScript Streaming Redaction with Node.js Source: https://docs.modulate.ai/api-reference/redaction/streaming This Node.js example demonstrates how to connect to the Streaming Redaction API using the `ws` library. It sends audio chunks and processes incoming messages for transcriptions and redacted audio. Ensure `ws` and `fs` modules are available. ```javascript const WebSocket = require("ws"); const fs = require("fs"); const API_KEY = "YOUR_API_KEY"; const AUDIO_FILE = "recording.ogg"; const CHUNK_SIZE = 8192; const url = new URL( "wss://modulate-developer-apis.com/api/velma-2-pii-phi-redaction-streaming" ); url.searchParams.set("api_key", API_KEY); url.searchParams.set("speaker_diarization", "true"); url.searchParams.set("start_redaction_padding_ms", "100"); url.searchParams.set("end_redaction_padding_ms", "0"); const ws = new WebSocket(url.toString()); const utterances = []; const audioClips = []; let isDone = false; ws.on("open", () => { const stream = fs.createReadStream(AUDIO_FILE, { highWaterMark: CHUNK_SIZE }); stream.on("data", (chunk) => ws.send(chunk)); stream.on("end", () => ws.send("")); }); ws.on("message", (data, isBinary) => { if (isBinary) { audioClips.push(data); if (isDone) finalize(); return; } const msg = JSON.parse(data.toString()); if (msg.type === "utterance") { utterances.push(msg.utterance); console.log( `[Speaker ${msg.utterance.speaker}] (${msg.utterance.language}) ` + `${msg.utterance.start_ms}ms: ${msg.utterance.text}` ); } else if (msg.type === "done") { console.log(`\nDone. Duration: ${msg.duration_ms}ms`); isDone = true; if (!msg.trailing_redacted_audio) finalize(); } else if (msg.type === "error") { console.error("Error:", msg.error); ws.close(); } }); function finalize() { if (audioClips.length > 0) { const combined = Buffer.concat(audioClips); fs.writeFileSync("redacted.mp3", combined); } ws.close(); } ws.on("error", (err) => console.error("WebSocket error:", err.message)); ``` -------------------------------- ### Python Streaming Redaction with aiohttp Source: https://docs.modulate.ai/api-reference/redaction/streaming Use this snippet to stream audio to the Redaction API and receive redacted audio and transcriptions. Ensure you have the `aiohttp` library installed. The API key and audio file path must be configured. ```python import asyncio import json import aiohttp API_KEY = "YOUR_API_KEY" AUDIO_FILE = "recording.ogg" CHUNK_SIZE = 8192 async def redact_streaming(): url = ( "wss://modulate-developer-apis.com/api/velma-2-pii-phi-redaction-streaming" f"?api_key={API_KEY}" "&speaker_diarization=true" "&start_redaction_padding_ms=100" "&end_redaction_padding_ms=0" ) utterances = [] audio_clips = [] async with aiohttp.ClientSession() as session: async with session.ws_connect(url) as ws: async def send_audio(): with open(AUDIO_FILE, "rb") as f: while chunk := f.read(CHUNK_SIZE): await ws.send_bytes(chunk) await asyncio.sleep(CHUNK_SIZE / 4000) await ws.send_str("") send_task = asyncio.create_task(send_audio()) try: done = False async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: data = json.loads(msg.data) if data["type"] == "utterance": u = data["utterance"] utterances.append(u) print(f"[Speaker {u['speaker']}] ({u['language']}) {u['start_ms']}ms: {u['text']}") elif data["type"] == "done": print(f"\nDone. Duration: {data['duration_ms']}ms") done = True if not data.get("trailing_redacted_audio"): break elif data["type"] == "error": print(f"Error: {data['error']}") break elif msg.type == aiohttp.WSMsgType.BINARY: audio_clips.append(msg.data) if done: break elif msg.type in ( aiohttp.WSMsgType.ERROR, aiohttp.WSMsgType.CLOSE, aiohttp.WSMsgType.CLOSED, ): break finally: if not send_task.done(): send_task.cancel() if audio_clips: with open("redacted.mp3", "wb") as f: for clip in audio_clips: f.write(clip) asyncio.run(redact_streaming()) ``` -------------------------------- ### Stream Audio for Transcription (JavaScript Node.js) Source: https://docs.modulate.ai/api-reference/stt/streaming This JavaScript snippet demonstrates how to stream audio for real-time transcription using Node.js and the `ws` library. It connects to the WebSocket endpoint, sends audio chunks, and handles incoming messages for utterances and completion status. Ensure you have the `ws` package installed. ```javascript const WebSocket = require("ws"); const fs = require("fs"); const API_KEY = "YOUR_API_KEY"; const AUDIO_FILE = "recording.opus"; const CHUNK_SIZE = 8192; const url = new URL("wss://modulate-developer-apis.com/api/velma-2-stt-streaming"); url.searchParams.set("api_key", API_KEY); url.searchParams.set("speaker_diarization", "true"); url.searchParams.set("emotion_signal", "true"); const ws = new WebSocket(url.toString()); const utterances = []; ws.on("open", () => { const stream = fs.createReadStream(AUDIO_FILE, { highWaterMark: CHUNK_SIZE }); stream.on("data", (chunk) => ws.send(chunk)); stream.on("end", () => ws.send("")); }); ws.on("message", (data) => { const msg = JSON.parse(data.toString()); if (msg.type === "utterance") { utterances.push(msg.utterance); console.log(`[Speaker ${msg.utterance.speaker}] ${msg.utterance.text}`); } else if (msg.type === "done") { console.log(`Done. Duration: ${msg.duration_ms}ms`); console.log("Transcript:", utterances.map((u) => u.text).join(" ")); ws.close(); } else if (msg.type === "error") { console.error("Error:", msg.error); ws.close(); } }); ws.on("error", (err) => console.error("WebSocket error:", err.message)); ``` -------------------------------- ### Python: Asynchronous Authentication (aiohttp) Source: https://docs.modulate.ai/guides/code-examples Shows how to set up an asynchronous HTTP client session using 'aiohttp' with the API key included in the headers. This session can be reused for multiple requests. ```python import aiohttp async with aiohttp.ClientSession(headers={"X-API-Key": "YOUR_API_KEY"}) as session: # reuse session for multiple requests pass ``` -------------------------------- ### Add API Key Header for Authentication Source: https://docs.modulate.ai/guides/troubleshooting Ensure the `X-API-Key` header is correctly cased and included in your requests to avoid `401 Unauthorized` errors. ```bash curl -H "X-API-Key: your_api_key_here" ... ``` -------------------------------- ### Python: Synchronous Authentication (requests) Source: https://docs.modulate.ai/guides/code-examples Demonstrates how to authenticate synchronous API requests using the 'requests' library by passing the API key in the headers. It's recommended to reuse the session or headers for multiple requests. ```python import requests HEADERS = {"X-API-Key": "YOUR_API_KEY"} response = requests.post( "https://modulate-developer-apis.com/api/velma-2-stt-batch", headers=HEADERS, files={"upload_file": open("recording.mp3", "rb")}, data={"speaker_diarization": "true"}, ) response.raise_for_status() result = response.json() ``` -------------------------------- ### Stream Audio for Transcription (Python aiohttp) Source: https://docs.modulate.ai/api-reference/stt/streaming Use this snippet to stream audio data in real-time for transcription. It connects to the WebSocket API, sends audio chunks, and processes transcription results including speaker information and emotions. Ensure you have the `aiohttp` library installed. ```python import asyncio import json import aiohttp API_KEY = "YOUR_API_KEY" AUDIO_FILE = "recording.opus" CHUNK_SIZE = 8192 async def transcribe_streaming(): url = ( f"wss://modulate-developer-apis.com/api/velma-2-stt-streaming" f"?api_key={API_KEY}" f"&speaker_diarization=true" f"&emotion_signal=true" f"&accent_signal=true" ) utterances = [] async with aiohttp.ClientSession() as session: async with session.ws_connect(url) as ws: async def send_audio(): with open(AUDIO_FILE, "rb") as f: while chunk := f.read(CHUNK_SIZE): await ws.send_bytes(chunk) await asyncio.sleep(CHUNK_SIZE / 4000) await ws.send_str("") send_task = asyncio.create_task(send_audio()) try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: data = json.loads(msg.data) if data["type"] == "utterance": u = data["utterance"] utterances.append(u) print(f"[Speaker {u['speaker']}] {u['text']}") elif data["type"] == "done": print(f"Done. Duration: {data['duration_ms']}ms") break elif data["type"] == "error": print(f"Error: {data['error']}") break elif msg.type in ( aiohttp.WSMsgType.ERROR, aiohttp.WSMsgType.CLOSE, aiohttp.WSMsgType.CLOSED, ): break finally: if not send_task.done(): send_task.cancel() full_text = " ".join(u["text"] for u in utterances) print(f"\nFull transcript:\n{full_text}") asyncio.run(transcribe_streaming()) ``` -------------------------------- ### Connect to SVD Streaming with Raw PCM Format Source: https://docs.modulate.ai/guides/audio-formats Connect to the SVD streaming endpoint using a raw PCM format. This requires specifying `audio_format`, `sample_rate`, and `num_channels` as query parameters since the server cannot infer these from headerless audio data. ```text wss://...?api_key=YOUR_API_KEY&audio_format=s16le&sample_rate=16000&num_channels=1 ``` -------------------------------- ### Connect to SVD Streaming with Container Format Source: https://docs.modulate.ai/guides/audio-formats Use this URL structure to connect to the SVD streaming endpoint with a container audio format like WebM. The `audio_format` parameter specifies the container type. ```text wss://...?api_key=YOUR_API_KEY&audio_format=webm ``` -------------------------------- ### cURL: Batch File Upload with Optional Features Source: https://docs.modulate.ai/guides/code-examples Use this cURL command to upload audio files for batch processing with optional features like speaker diarization and emotion signal extraction. Replace YOUR_API_KEY and the file path with your actual values. ```bash curl -X POST https://modulate-developer-apis.com/api/velma-2-stt-batch \ -H "X-API-Key: YOUR_API_KEY" \ -F "upload_file=@/path/to/recording.mp3" \ -F "speaker_diarization=true" \ -F "emotion_signal=true" \ -F "accent_signal=false" \ -F "pii_phi_tagging=false" ``` -------------------------------- ### WebSocket Streaming Transcription (Python) Source: https://docs.modulate.ai/guides/code-examples Demonstrates real-time audio transcription using WebSockets with aiohttp. Requires API key and an audio file. ```python import asyncio import json import aiohttp API_KEY = "YOUR_API_KEY" AUDIO_FILE = "recording.opus" CHUNK_SIZE = 8192 async def stream_transcription(): url = ( f"wss://modulate-developer-apis.com/api/velma-2-stt-streaming" f"?api_key={API_KEY}" f"&speaker_diarization=true" f"&emotion_signal=true" ) async with aiohttp.ClientSession() as session: async with session.ws_connect(url) as ws: async def send_audio(): with open(AUDIO_FILE, "rb") as f: while chunk := f.read(CHUNK_SIZE): await ws.send_bytes(chunk) await asyncio.sleep(CHUNK_SIZE / 4000) await ws.send_str("") send_task = asyncio.create_task(send_audio()) try: async for msg in ws: if msg.type == aiohttp.WSMsgType.TEXT: data = json.loads(msg.data) if data["type"] == "utterance": u = data["utterance"] print(f"[Speaker {u['speaker']}] {u['text']}") elif data["type"] == "done": print(f"Done. Duration: {data['duration_ms']}ms") break elif data["type"] == "error": print(f"Error: {data['error']}") break elif msg.type in ( aiohttp.WSMsgType.ERROR, aiohttp.WSMsgType.CLOSE, aiohttp.WSMsgType.CLOSED, ): break finally: if not send_task.done(): send_task.cancel() asyncio.run(stream_transcription()) ``` -------------------------------- ### Streaming Endpoint with Authentication Source: https://docs.modulate.ai/api-reference/svd/streaming Connect to the streaming API endpoint, including your API key and audio format parameters. Ensure the API key is in the query string, not a header. ```text wss://modulate-developer-apis.com/api/velma-2-synthetic-voice-detection-streaming?api_key=YOUR_API_KEY&audio_format=s16le&sample_rate=16000&num_channels=1 ``` -------------------------------- ### Batch File Upload with Native Fetch (Node.js) Source: https://docs.modulate.ai/guides/code-examples Uploads audio files in batch using Node.js native `fetch` (available in Node 18+). Reads the entire file into memory. ```javascript import fs from "fs"; import path from "path"; const API_KEY = "YOUR_API_KEY"; async function transcribe(filePath) { const formData = new FormData(); formData.append( "upload_file", new Blob([fs.readFileSync(filePath)]), path.basename(filePath) ); formData.append("speaker_diarization", "true"); formData.append("emotion_signal", "true"); const response = await fetch( "https://modulate-developer-apis.com/api/velma-2-stt-batch", { method: "POST", headers: { "X-API-Key": API_KEY }, body: formData, } ); if (!response.ok) { const err = await response.json().catch(() => ({ detail: response.statusText })); throw new Error(`${response.status}: ${err.detail}`); } return response.json(); } const result = await transcribe("recording.mp3"); console.log(result.text); for (const u of result.utterances) { console.log(`[Speaker ${u.speaker}] (${u.language}) ${u.text}`); } ``` -------------------------------- ### Store API key securely Source: https://docs.modulate.ai/quickstart Avoid hard-coding credentials by storing your API key in a .env file and adding it to .gitignore. ```bash MODULATE_API_KEY=your_api_key_here ``` ```bash echo ".env" >> .gitignore ``` -------------------------------- ### Batch File Upload with form-data Package (Node.js) Source: https://docs.modulate.ai/guides/code-examples Uploads audio files in batch using the `form-data` package, suitable for Node.js versions prior to 18 or when streaming files is preferred. This method avoids loading the entire file into memory. ```javascript import fs from "fs"; import path from "path"; import FormData from "form-data"; const API_KEY = "YOUR_API_KEY"; async function transcribe(filePath) { const form = new FormData(); form.append("upload_file", fs.createReadStream(filePath), { filename: path.basename(filePath), }); form.append("speaker_diarization", "true"); const response = await fetch( "https://modulate-developer-apis.com/api/velma-2-stt-batch", { method: "POST", headers: { "X-API-Key": API_KEY, ...form.getHeaders(), }, body: form, } ); if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`); return response.json(); } ``` -------------------------------- ### Detect Deepfake in Audio File (Batch) Source: https://docs.modulate.ai/quickstart Use this Python script to send an audio file to the batch deepfake detection API. It processes the entire file and returns results for time-windowed frames. Ensure you have your API key set as an environment variable and the audio file in the same directory. ```python import os import requests from dotenv import load_dotenv load_dotenv() API_KEY = os.environ["MODULATE_API_KEY"] ENDPOINT = "https://modulate-developer-apis.com/api/velma-2-synthetic-voice-detection-batch" AUDIO_FILE = "audio.mp3" VERDICT_LABELS = { "synthetic": "Synthetic (AI-generated)", "non-synthetic": "Non-synthetic (human)", "no-content": "No content (silence)", } def detect_deepfake(filepath: str) -> dict: headers = {"X-API-Key": API_KEY} with open(filepath, "rb") as f: response = requests.post(ENDPOINT, headers=headers, files={"upload_file": f}) response.raise_for_status() return response.json() if __name__ == "__main__": result = detect_deepfake(AUDIO_FILE) print(f"\nFile: {result['filename']}") print(f"Duration: {result['duration_ms']} ms") print(f"Frames: {len(result['frames'])}\n") for frame in result["frames"]: label = VERDICT_LABELS.get(frame["verdict"], frame["verdict"]) print( f" {frame['start_time_ms']:>6}ms – {frame['end_time_ms']:>6}ms " f"{label} (confidence: {frame['confidence']:.2%})" ) ``` -------------------------------- ### Convert Audio to Raw PCM Format Source: https://docs.modulate.ai/guides/troubleshooting Convert audio files to raw PCM format using FFmpeg before sending them to the SVD Streaming endpoint to avoid `400 Bad Request` errors. ```bash ffmpeg -i input.mp3 -ar 16000 -ac 1 -f s16le output.raw ``` -------------------------------- ### REST API Key Authentication Header Source: https://docs.modulate.ai/faq Pass your API key in the `X-API-Key` header for authentication with REST endpoints. ```bash X-API-Key: your_api_key_here ``` -------------------------------- ### Convert Audio to Opus Format Source: https://docs.modulate.ai/guides/troubleshooting Convert audio files to Opus format using FFmpeg before sending them to the STT Batch English VFast endpoint to avoid `400 Bad Request` errors. ```bash ffmpeg -i input.mp3 output.opus ``` -------------------------------- ### Provide API Key for WebSocket Connection Source: https://docs.modulate.ai/guides/troubleshooting Include the `api_key` query parameter when establishing a WebSocket connection to prevent `4001` close codes. ```text wss://modulate-developer-apis.com/api/velma-2-stt-streaming?api_key=your_api_key_here ``` -------------------------------- ### Python: Asynchronous Batch File Upload (aiohttp) Source: https://docs.modulate.ai/guides/code-examples An asynchronous function using 'aiohttp' to upload a file for batch processing. It includes optional features like speaker diarization and emotion signal. The function handles session creation and response parsing. ```python import asyncio import aiohttp async def transcribe(file_path: str) -> dict: data = aiohttp.FormData() data.add_field( "upload_file", open(file_path, "rb"), filename=file_path.split("/")[-1], content_type="application/octet-stream", ) data.add_field("speaker_diarization", "true") data.add_field("emotion_signal", "true") async with aiohttp.ClientSession(headers={"X-API-Key": "YOUR_API_KEY"}) as session: async with session.post( "https://modulate-developer-apis.com/api/velma-2-stt-batch", data=data, ) as resp: resp.raise_for_status() return await resp.json() result = asyncio.run(transcribe("recording.mp3")) ``` -------------------------------- ### Inspect Audio Duration with ffprobe Source: https://docs.modulate.ai/guides/troubleshooting Use ffprobe to check the actual audio duration of a file. This helps diagnose 'audio too short' errors. ```bash ffprobe -v quiet -show_entries format=duration -of csv=p=0 yourfile.wav ``` -------------------------------- ### Convert audio to Opus format using ffmpeg Source: https://docs.modulate.ai/quickstart Use this command to convert audio files to the Opus format, which is required by the batch English transcription model. ```bash ffmpeg -i audio.mp3 audio.opus ``` -------------------------------- ### Connection Flow Source: https://docs.modulate.ai/api-reference/svd/streaming The connection flow involves establishing a WebSocket connection with authentication and audio format parameters, streaming binary audio frames, receiving JSON messages for analysis results, and signaling the end of audio with an empty text frame. ```APIDOC ## Connection Flow 1. Connect with `api_key`, `audio_format`, and (for raw formats) `sample_rate` and `num_channels`. 2. Stream audio as **binary** WebSocket frames. Frames can be any size. 3. Receive `frame` JSON messages as analysis windows complete. 4. Send an **empty text frame** (`""`) to signal end of audio. 5. Receive a `done` message with total duration and frame count. 6. The connection closes automatically. ``` -------------------------------- ### Stream Deepfake Detection (WebSocket) Source: https://docs.modulate.ai/quickstart This Python script connects to the streaming deepfake detection WebSocket API to analyze raw PCM audio data in real-time. It sends audio chunks and receives frame-by-frame results. Configure the URL with your API key and audio format parameters. Ensure the audio file is in raw PCM format (e.g., s16le, 16kHz, mono). ```python import os import asyncio import json import websockets from dotenv import load_dotenv load_dotenv() API_KEY = os.environ["MODULATE_API_KEY"] BASE_URL = "wss://modulate-developer-apis.com/api/velma-2-synthetic-voice-detection-streaming" AUDIO_FILE = "audio.raw" CHUNK_SIZE = 8192 def build_url() -> str: params = { "api_key": API_KEY, "audio_format": "s16le", "sample_rate": "16000", "num_channels": "1", } query = "&".join(f"{k}={v}" for k, v in params.items()) return f"{BASE_URL}?{query}" async def stream_detection(filepath: str): url = build_url() async with websockets.connect(url) as ws: async def send_audio(): with open(filepath, "rb") as f: while chunk := f.read(CHUNK_SIZE): await ws.send(chunk) await asyncio.sleep(0) await ws.send("") async def receive_results(): async for message in ws: msg = json.loads(message) if msg.get("type") == "frame": frame = msg["frame"] print( f" {frame['start_time_ms']:>6}ms – {frame['end_time_ms']:>6}ms " f"{frame['verdict']} (confidence: {frame['confidence']:.2%})" ) elif msg.get("type") == "done": print(f"\nDone. Total: {msg['duration_ms']} ms, frames: {msg['frame_count']}") break elif msg.get("type") == "error": print(f"Error: {msg['error']}") break await asyncio.gather(send_audio(), receive_results()) if __name__ == "__main__": asyncio.run(stream_detection(AUDIO_FILE)) ``` -------------------------------- ### Deepfake Detection - Batch Source: https://docs.modulate.ai/api-reference Detects deepfakes in audio files using batch processing. Submit audio files for analysis to determine if they are synthetic. ```APIDOC ## POST /v1/deepfake/batch ### Description Analyzes audio files in batches to detect deepfakes. ### Method POST ### Endpoint /v1/deepfake/batch ### Parameters #### Request Body - **audio_file** (file) - Required - The audio file to analyze for deepfakes. ### Request Example ```json { "audio_file": "@/path/to/your/audio.wav" } ``` ### Response #### Success Response (200) - **is_deepfake** (boolean) - True if the audio is detected as a deepfake, false otherwise. - **confidence** (number) - The confidence score of the deepfake detection. #### Response Example ```json { "is_deepfake": true, "confidence": 0.98 } ``` ``` -------------------------------- ### PII/PHI Redaction - Streaming (WebSocket) Source: https://docs.modulate.ai/quickstart Use this endpoint for live audio where you need PII/PHI redacted in real time. Redacted transcript text and redacted MP3 clips are delivered as each utterance completes. Supported formats include self-describing formats like WAV, MP3, OGG, FLAC, WebM, AAC, AIFF, and raw PCM formats if audio format details are provided. ```APIDOC ## PII/PHI redaction — streaming (WebSocket) ### Description Redacts PII/PHI from live audio in real time, delivering redacted transcript text and audio clips as utterances complete. ### Method `WebSocket` ### Endpoint `wss://modulate-developer-apis.com/api/velma-2-pii-phi-redaction-streaming` ### Parameters #### Query Parameters - **api_key** (string) - Required - Your Modulate API key. - **speaker_diarization** (string) - Optional - Set to `true` to enable speaker diarization. - **start_redaction_padding_ms** (string) - Optional - Padding in milliseconds to add before redaction starts. Defaults to `100`. - **end_redaction_padding_ms** (string) - Optional - Padding in milliseconds to add after redaction ends. Defaults to `0`. - **audio_format** (string) - Required for raw PCM - The audio format (e.g., `pcm_s16le`). - **sample_rate** (integer) - Required for raw PCM - The audio sample rate (e.g., `16000`). - **num_channels** (integer) - Required for raw PCM - The number of audio channels (e.g., `1`). ### Request Example ```python import asyncio import websockets import json API_KEY = "YOUR_API_KEY" BASE_URL = "wss://modulate-developer-apis.com/api/velma-2-pii-phi-redaction-streaming" AUDIO_FILE = "audio.mp3" CHUNK_SIZE = 4096 def build_url() -> str: params = { "api_key": API_KEY, "speaker_diarization": "true", "start_redaction_padding_ms": "100", "end_redaction_padding_ms": "0", } query = "&".join(f"{k}={v}" for k, v in params.items()) return f"{BASE_URL}?{query}" async def redact_streaming(filepath: str): url = build_url() audio_clips = [] async with websockets.connect(url) as ws: async def send_audio(): with open(filepath, "rb") as f: while chunk := f.read(CHUNK_SIZE): await ws.send(chunk) await asyncio.sleep(0) await ws.send("") # Signal end of audio async def receive_results(): is_done = False async for message in ws: if isinstance(message, bytes): audio_clips.append(message) if is_done: break continue msg = json.loads(message) if msg.get("type") == "utterance": u = msg["utterance"] print(f"[{u['start_ms']}ms] Speaker {u['speaker']}: {u['text']}") elif msg.get("type") == "done": is_done = True if not msg.get("trailing_redacted_audio"): break elif msg.get("type") == "error": print(f"Error: {msg['error']}") break await asyncio.gather(send_audio(), receive_results()) if audio_clips: with open("redacted.mp3", "wb") as f: for clip in audio_clips: f.write(clip) if __name__ == "__main__": asyncio.run(redact_streaming(AUDIO_FILE)) ``` ### Response Messages are received as JSON objects or binary audio data: - **Utterance Message**: `{"type": "utterance", "utterance": {"start_ms": integer, "speaker": string, "text": string}}` - **Done Message**: `{"type": "done", "trailing_redacted_audio": boolean}` - **Error Message**: `{"type": "error", "error": string}` - **Binary Audio**: Redacted audio clips. ``` -------------------------------- ### Batch Transcription (Multilingual) Source: https://docs.modulate.ai/quickstart Transcribe a complete audio file using the batch transcription endpoint. This provides per-utterance timing, speaker labels, and optional enrichments. ```APIDOC ## POST /api/velma-2-stt-batch ### Description Transcribe a complete audio file using the batch transcription endpoint. This provides per-utterance timing, speaker labels, and optional enrichments. ### Method POST ### Endpoint /api/velma-2-stt-batch ### Parameters #### Query Parameters - **speaker_diarization** (boolean) - Optional - Enable speaker diarization. - **emotion_signal** (boolean) - Optional - Enable emotion signal detection. - **accent_signal** (boolean) - Optional - Enable accent signal detection. - **deepfake_signal** (boolean) - Optional - Enable deepfake signal detection. - **pii_phi_tagging** (boolean) - Optional - Enable PII/PHI tagging. #### Request Body - **upload_file** (file) - Required - The audio file to transcribe. Supported formats: AAC, AIFF, FLAC, MP3, MP4, MOV, OGG, Opus, WAV, WebM. ### Request Example ```python import os import requests from dotenv import load_dotenv load_dotenv() API_KEY = os.environ["MODULATE_API_KEY"] ENDPOINT = "https://modulate-developer-apis.com/api/velma-2-stt-batch" AUDIO_FILE = "audio.mp3" def transcribe(filepath: str) -> dict: headers = {"X-API-Key": API_KEY} params = { "speaker_diarization": True, "emotion_signal": False, "accent_signal": False, "deepfake_signal": False, "pii_phi_tagging": False, } with open(filepath, "rb") as f: response = requests.post( ENDPOINT, headers=headers, data=params, files={"upload_file": f}, ) response.raise_for_status() return response.json() if __name__ == "__main__": result = transcribe(AUDIO_FILE) print("\n── Transcript ──") print(result["text"]) print(f"\n── Duration: {result['duration_ms']} ms ──") print(f"\n── Utterances ({len(result['utterances'])} total) ──") for u in result["utterances"]: print( f" [{u['start_ms']}ms] Speaker {u['speaker']} ({u['language']}): " f"{u['text']}" ) ``` ### Response #### Success Response (200) - **text** (string) - The full transcript of the audio. - **duration_ms** (integer) - The duration of the audio in milliseconds. - **utterances** (array) - A list of detected utterances. - **start_ms** (integer) - The start time of the utterance in milliseconds. - **end_ms** (integer) - The end time of the utterance in milliseconds. - **speaker** (string) - The identified speaker label. - **language** (string) - The detected language of the utterance. - **text** (string) - The transcribed text of the utterance. #### Response Example ```json { "text": "Hello everyone. Welcome to the meeting. We'll be discussing results today.", "duration_ms": 8400, "utterances": [ { "start_ms": 0, "end_ms": 4200, "speaker": "Speaker 1", "language": "en", "text": "Hello everyone. Welcome to the meeting." }, { "start_ms": 4200, "end_ms": 8400, "speaker": "Speaker 1", "language": "en", "text": "We'll be discussing results today." } ] } ``` ``` -------------------------------- ### WebSocket Endpoint with API Key Source: https://docs.modulate.ai/api-reference/redaction/streaming Connect to the WebSocket endpoint for real-time PII/PHI redaction. Pass your API key as a query parameter. ```APIDOC ## WebSocket Endpoint ### Description Connect to the WebSocket endpoint to initiate real-time PII/PHI redaction. Your API key must be provided as a query parameter. ### Endpoint `wss://modulate-developer-apis.com/api/velma-2-pii-phi-redaction-streaming?api_key=YOUR_API_KEY` ### Authentication Pass your API key as a query parameter named `api_key` when opening the connection. Unlike batch endpoints, the streaming API does not use an `X-API-Key` header. ### Query Parameters - **api_key** (string) - Required. Your API key. - **speaker_diarization** (boolean) - Optional. Identify and label distinct speakers. Defaults to `true`. - **audio_format** (string) - Optional. Audio encoding format. Omit for self-describing formats; required for raw formats. - **sample_rate** (integer) - Required for raw formats only. Sample rate in Hz. - **num_channels** (integer) - Required for raw formats only. Number of channels (1–8). - **start_redaction_padding_ms** (integer) - Optional. Extra silence (ms) prepended before each redacted audio range. Defaults to `100`. - **end_redaction_padding_ms** (integer) - Optional. Extra silence (ms) appended after each redacted audio range. Defaults to `0`. ``` -------------------------------- ### Transcribe audio using Velma-2 batch API Source: https://docs.modulate.ai/quickstart Sends an audio file to the Velma-2 batch transcription API and retrieves the transcript with utterance timing and speaker labels. Ensure your API key is set in the environment and the audio file is in the project directory. ```python import os import requests from dotenv import load_dotenv load_dotenv() API_KEY = os.environ["MODULATE_API_KEY"] ENDPOINT = "https://modulate-developer-apis.com/api/velma-2-stt-batch" AUDIO_FILE = "audio.mp3" def transcribe(filepath: str) -> dict: headers = {"X-API-Key": API_KEY} params = { "speaker_diarization": True, "emotion_signal": False, "accent_signal": False, "deepfake_signal": False, "pii_phi_tagging": False, } with open(filepath, "rb") as f: response = requests.post( ENDPOINT, headers=headers, data=params, files={"upload_file": f}, ) response.raise_for_status() return response.json() if __name__ == "__main__": result = transcribe(AUDIO_FILE) print("\n── Transcript ──") print(result["text"]) print(f"\n── Duration: {result['duration_ms']} ms ──") print(f"\n── Utterances ({len(result['utterances'])} total) ──") for u in result["utterances"]: print( f" [{u['start_ms']}ms] Speaker {u['speaker']} ({u['language']}): " f"{u['text']}" ) ``` ```bash python stt_batch.py ```