Skip to main content
This guide walks you through the complete workflow: creating a dataset, uploading audio, adding annotations, training a model, and running inference.

Prerequisites

Step 1: Get your API key

  1. Sign in to app.relayai.dev
  2. Navigate to Settings > API Keys
  3. Click Create API Key
  4. Copy and save your key securely
API keys are only shown once. Store your key in a secure location.
Set your API key as an environment variable:
export RELAY_API_KEY="your_api_key_here"

Step 2: Create a dataset

A dataset defines what artifact types you want to detect. Create one with the artifact types relevant to your use case:
curl -X POST https://api.relayai.dev/api/v1/datasets \
  -H "X-API-Key: $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "TTS Glitch Detection",
    "description": "Detect glitches and pauses in TTS output",
    "artifact_types": [
      {"name": "glitch", "description": "Audio pop or click", "color": "#FF4444"},
      {"name": "long_pause", "description": "Unnatural pause > 500ms", "color": "#4444FF"}
    ]
  }'
Response:
{
  "id": "123e4567-e89b-12d3-a456-426614174000",
  "name": "TTS Glitch Detection",
  "description": "Detect glitches and pauses in TTS output",
  "artifact_types": [
    {"name": "glitch", "description": "Audio pop or click", "color": "#FF4444"},
    {"name": "long_pause", "description": "Unnatural pause > 500ms", "color": "#4444FF"}
  ],
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-01-15T10:30:00Z"
}
Save the id from the response. You’ll need it for subsequent steps.

Step 3: Upload audio files

Audio upload uses presigned URLs for direct upload to cloud storage. The flow is:
  1. Request a presigned upload URL
  2. Upload the file to the URL
  3. Confirm the upload

Request upload URL

curl -X POST "https://api.relayai.dev/api/v1/datasets/$DATASET_ID/audio/upload-url" \
  -H "X-API-Key: $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filename": "sample_audio.wav",
    "content_type": "audio/wav",
    "file_size": 1048576
  }'
Response:
{
  "upload_url": "https://s3.amazonaws.com/...",
  "fields": {
    "key": "uploads/123/sample_audio.wav",
    "policy": "...",
    "x-amz-signature": "..."
  },
  "audio_id": "456e7890-e89b-12d3-a456-426614174001",
  "expires_in": 3600
}

Upload the file

# Upload using the presigned URL (multipart form)
curl -X POST "$UPLOAD_URL" \
  -F "key=$KEY" \
  -F "policy=$POLICY" \
  -F "x-amz-signature=$SIGNATURE" \
  -F "file=@sample_audio.wav"

Confirm upload

curl -X POST "https://api.relayai.dev/api/v1/datasets/$DATASET_ID/audio/confirm" \
  -H "X-API-Key: $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "audio_id": "456e7890-e89b-12d3-a456-426614174001"
  }'
After confirmation, Relay processes the audio (normalizes to 16kHz mono and computes embeddings). Check the audio file status by polling:
Python
# Wait for processing to complete
import time

while True:
    response = requests.get(
        f"{BASE_URL}/api/v1/datasets/{dataset_id}/audio/{audio_id}",
        headers={"X-API-Key": API_KEY}
    )
    audio = response.json()
    if audio["processing_status"] == "ready":
        print("Audio processing complete")
        break
    elif audio["processing_status"] == "failed":
        print(f"Processing failed: {audio['processing_error']}")
        break
    time.sleep(2)

Step 4: Add annotations

Create an annotation set and add annotations marking where artifacts occur:

Create annotation set

curl -X POST "https://api.relayai.dev/api/v1/datasets/$DATASET_ID/annotation-sets" \
  -H "X-API-Key: $RELAY_API_KEY"

Add annotations

Each annotation specifies which audio file, the artifact type, and the start/end timestamps in milliseconds:
curl -X POST "https://api.relayai.dev/api/v1/datasets/$DATASET_ID/annotation-sets/$ANNOTATION_SET_ID/annotations/bulk" \
  -H "X-API-Key: $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "annotations": [
      {
        "audio_file_id": "456e7890-e89b-12d3-a456-426614174001",
        "artifact_type": "glitch",
        "start_ms": 1200,
        "end_ms": 1450,
        "confidence": 1.0
      },
      {
        "audio_file_id": "456e7890-e89b-12d3-a456-426614174001",
        "artifact_type": "long_pause",
        "start_ms": 3500,
        "end_ms": 4200,
        "confidence": 1.0
      }
    ]
  }'

Publish the annotation set

Before training, you must publish the annotation set. Published sets are immutable.
curl -X POST "https://api.relayai.dev/api/v1/datasets/$DATASET_ID/annotation-sets/$ANNOTATION_SET_ID/publish" \
  -H "X-API-Key: $RELAY_API_KEY"

Step 5: Train a model

Submit a training job with your dataset and published annotation set:
curl -X POST https://api.relayai.dev/api/v1/training-jobs \
  -H "X-API-Key: $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "dataset_id": "123e4567-e89b-12d3-a456-426614174000",
    "annotation_set_id": "789e0123-e89b-12d3-a456-426614174002",
    "config": {
      "artifact_types": ["glitch", "long_pause"],
      "epochs": 20,
      "validation_split": 0.2,
      "learning_rate": 0.001,
      "batch_size": 32
    }
  }'
Poll for training completion:
Python
while True:
    response = requests.get(
        f"{BASE_URL}/api/v1/training-jobs/{job_id}",
        headers={"X-API-Key": API_KEY}
    )
    job = response.json()
    print(f"Status: {job['status']} - Progress: {job['progress_percent']}%")

    if job["status"] == "completed":
        print(f"Training complete! Metrics: {job['metrics']}")
        break
    elif job["status"] == "failed":
        print(f"Training failed: {job['error_message']}")
        break
    time.sleep(30)

Step 6: Run inference

Once training completes, a model is created automatically. Create an inference job and upload audio to detect artifacts:

Create inference job

curl -X POST https://api.relayai.dev/api/v1/inference-jobs \
  -H "X-API-Key: $RELAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model_id": "model-uuid-here",
    "config": {
      "threshold": 0.5,
      "merge_window_ms": 200,
      "min_duration_ms": 50
    }
  }'

Upload audio for inference

Upload audio using the same presigned URL flow:
Python
# Get upload URL
response = requests.post(
    f"{BASE_URL}/api/v1/inference-jobs/{inference_job_id}/files/upload-url",
    headers={"X-API-Key": API_KEY},
    json={
        "filename": "test_audio.wav",
        "content_type": "audio/wav",
        "file_size_bytes": 2097152
    }
)
upload_info = response.json()

# Upload file
with open("test_audio.wav", "rb") as f:
    requests.post(
        upload_info["upload_url"],
        data=upload_info["upload_fields"],
        files={"file": f}
    )

# Confirm upload
requests.post(
    f"{BASE_URL}/api/v1/inference-jobs/{inference_job_id}/files/confirm",
    headers={"X-API-Key": API_KEY},
    json={"file_id": upload_info["file_id"]}
)

Get detection results

curl "https://api.relayai.dev/api/v1/inference-jobs/$INFERENCE_JOB_ID" \
  -H "X-API-Key: $RELAY_API_KEY"
Example response:
{
  "id": "job-uuid",
  "status": "completed",
  "total_files": 1,
  "processed_files": 1,
  "total_detections": 2,
  "files": [
    {
      "original_filename": "test_audio.wav",
      "status": "completed",
      "detections": [
        {
          "artifact_type": "glitch",
          "start_ms": 1200,
          "end_ms": 1450,
          "confidence": 0.87
        },
        {
          "artifact_type": "long_pause",
          "start_ms": 3500,
          "end_ms": 4200,
          "confidence": 0.92
        }
      ]
    }
  ]
}

Next steps