> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sunbird.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Speech to Text

> Convert audio to text in multiple languages

The Speech to Text (STT) service transcribes audio files into text across multiple Ugandan languages and English. The unified **`POST /tasks/audio/transcriptions`** endpoint accepts an uploaded audio file (or a GCS object) and routes to the Modal (Whisper large-v3) or RunPod backend.

<Warning>
  **Migrating from the legacy STT routes?** `/tasks/stt`, `/tasks/modal/stt`, `/tasks/stt_from_gcs`, and `/tasks/org/stt` are **deprecated**. They still work but return `Deprecation`/`Sunset` headers. Switch to `/tasks/audio/transcriptions`.
</Warning>

## Supported Languages

| Language              | Code  |
| :-------------------- | :---- |
| **English (Ugandan)** | `eng` |
| **Swahili**           | `swa` |
| **Acholi**            | `ach` |
| **Lugbara**           | `lgg` |
| **Luganda**           | `lug` |
| **Runyankole**        | `nyn` |
| **Ateso**             | `teo` |
| **Lusoga**            | `xog` |
| **Rutooro**           | `ttj` |
| **Kinyarwanda**       | `kin` |
| **Lumasaba**          | `myx` |

## Audio Requirements

* **Formats**: MP3, WAV, M4A, and more.
* **Duration Limit**: For files larger than 100MB, only the first 10 minutes are transcribed.
* **File Size**: Direct uploads are supported. For larger files, use the signed-URL workflow described below.

## Transcribing a File (Modal / Whisper)

`language` is **required**. `platform` defaults to `modal` (Whisper large-v3).

<CodeGroup>
  ```python Python theme={null}
  import os
  import requests
  from dotenv import load_dotenv

  load_dotenv()

  url = "https://api.sunbird.ai/tasks/audio/transcriptions"
  access_token = os.getenv("AUTH_TOKEN")

  headers = {
      "accept": "application/json",
      "Authorization": f"Bearer {access_token}",
  }

  files = {
      "audio": ("recording.wav", open("/path/to/audio_file.wav", "rb"), "audio/wav"),
  }
  data = {
      "language": "lug",     # required: 3-letter code or full name (e.g. "Luganda")
      "platform": "modal",   # "modal" (default, Whisper) or "runpod" and optional
  }

  response = requests.post(url, headers=headers, files=files, data=data)
  result = response.json()
  print(f"Transcription: {result['audio_transcription']}")
  ```

  ```javascript JavaScript theme={null}
  const formData = new FormData();
  formData.append('audio', fileInput.files[0]);
  formData.append('language', 'lug');
  formData.append('platform', 'modal');

  const response = await fetch('https://api.sunbird.ai/tasks/audio/transcriptions', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer <YOUR_TOKEN>'
    },
    body: formData
  });
  console.log(await response.json());
  ```
</CodeGroup>

## Transcribing with RunPod (adapter, Whisper, diarization)

The RunPod backend adds a language `adapter`, the `whisper` flag, and optional speaker diarization (`recognise_speakers`).

```python theme={null}
files = {
    "audio": ("recording.mp3", open("/path/to/audio_file.mp3", "rb"), "audio/mpeg"),
}
data = {
    "language": "lug",
    "platform": "runpod",
    "adapter": "lug",             # optional; defaults to `language`
    "whisper": True,              # RunPod only
    "recognise_speakers": False,  # RunPod only — speaker diarization
}

response = requests.post(url, headers=headers, files=files, data=data)
print(response.json())
```

### Response

```json theme={null}
{
  "audio_transcription": "Ekibiina ekiddukanya ...",
  "language": "lug",
  "audio_url": "https://storage.googleapis.com/.../audio.wav?...",
  "audio_transcription_id": 123,
  "diarization_output": null,
  "formatted_diarization_output": null,
  "was_audio_trimmed": false,
  "original_duration_minutes": null
}
```

## Handling Large Files

To bypass server timeouts on large uploads, transcribe audio that already lives in Google Cloud Storage instead of uploading it inline.

<Steps>
  <Step title="Generate an Upload URL">
    Call `/tasks/generate-upload-url` to get a signed Google Cloud Storage URL (see [File Uploads](#file-uploads-signed-urls)).
  </Step>

  <Step title="Upload the File">
    `PUT` the file directly to that signed URL.
  </Step>

  <Step title="Transcribe">
    Call `/tasks/audio/transcriptions` with `platform="runpod"` and `gcs_blob_name` set to the uploaded object instead of an `audio` file.
  </Step>
</Steps>

## File Uploads (Signed URLs)

Generate secure signed URLs for direct client uploads to Google Cloud Storage. URLs are valid for **30 minutes** and include path-traversal protection.

```python theme={null}
import os
import requests
from dotenv import load_dotenv

load_dotenv()

# Step 1: Generate an upload URL
url = "https://api.sunbird.ai/tasks/generate-upload-url"
access_token = os.getenv("AUTH_TOKEN")

headers = {
    "accept": "application/json",
    "Authorization": f"Bearer {access_token}",
    "Content-Type": "application/json",
}

data = {"file_name": "recording.wav", "content_type": "audio/wav"}

response = requests.post(url, headers=headers, json=data)
result = response.json()

upload_url = result["upload_url"]
file_id = result["file_id"]
print(f"Upload URL: {upload_url}")
print(f"File ID: {file_id}")
print(f"Expires at: {result['expires_at']}")

# Step 2: Upload the file directly to GCS
with open("/path/to/your/recording.wav", "rb") as f:
    upload_response = requests.put(
        upload_url, data=f, headers={"Content-Type": "audio/wav"}
    )

if upload_response.status_code == 200:
    print("File uploaded successfully!")
```
