Skill: robotsbuildrobots/mai-voice (version 0.1.1)

--- name: mai-voice description: Synthesize speech with Microsoft's MAI-Voice-1 voices via Azure AI Speech REST API. homepage: https://learn.microsoft.com/en-us/azure/ai-services/speech-service/mai-voices metadata: {"clawdbot":{"emoji":"🗣️","requires":{"bins":["bash","curl"],"env":["AZURE_SPEECH_KEY","AZURE_SPEECH_REGION"]},"primaryEnv":"AZURE_SPEECH_KEY"}} --- # MAI-Voice-1 Synthesize speech with Azure AI Speech using Microsoft's **MAI-Voice-1** voices. ## Quick start ```bash {baseDir}/scripts/speak.sh --text "Hello Steve" ``` Defaults: - Voice: `en-us-Jasper:MAI-Voice-1` - Output: `./mai-voice.mp3` - Format: [REDACTED_SECRET] ## Useful flags ```bash {baseDir}/scripts/speak.sh --text "Hello Steve" --voice en-us-Iris:MAI-Voice-1 --out /tmp/iris.mp3 {baseDir}/scripts/speak.sh --text-file /tmp/input.txt --voice en-us-June:MAI-Voice-1 --style empathy --out /tmp/june.mp3 {baseDir}/scripts/speak.sh --text "Let's go" --voice en-us-Jasper:MAI-Voice-1 --style excitement {baseDir}/scripts/speak.sh --list-voices ``` ## Required env vars ```bash export AZURE_SPEECH_KEY="YOUR_SPEECH_RESOURCE_KEY" export AZURE_SPEECH_REGION="eastus" ``` ## How to get the API key and region 1. Go to the Azure portal and open your **Speech** or **Foundry Speech** resource. 2. Open **Keys and Endpoint**. 3. Copy one of the resource keys. 4. Copy the resource region, for example `eastus`. 5. Export them: ```bash export AZURE_SPEECH_KEY="YOUR_SPEECH_RESOURCE_KEY" export AZURE_SPEECH_REGION="eastus" ``` The MAI-Voice docs currently point at **East US** for preview access, so if you are not using `eastus`, double-check that your resource actually supports the model before blaming the script. Optional: ```bash export AZURE_SPEECH_OUTPUT_FORMAT=[REDACTED_SECRET] ``` ## Supported voices - `en-us-Jasper:MAI-Voice-1` - `en-us-June:MAI-Voice-1` - `en-us-Grant:MAI-Voice-1` - `en-us-Iris:MAI-Voice-1` - `en-us-Reed:MAI-Voice-1` - `en-us-Joy:MAI-Voice-1` ## API shape The script calls: ```text POST https://{AZURE_SPEECH_REGION}.tts.speech.microsoft.com/cognitiveservices/v1 ``` Headers: - `Ocp-Apim-Subscription-Key: {AZURE_SPEECH_KEY}` - `Content-Type: application/ssml+xml` - `X-Microsoft-OutputFormat: {format}` - `User-Agent: curl` Body: - SSML with a MAI voice name - optional `mstts:express-as` style wrapper ## Notes - This uses the Azure Speech REST API, not the Python SDK. - Voice selection is user-configurable. - Style is optional and applied via SSML. - MAI-Voice-1 is currently public preview.

path: README.md
content: # mai-voice

Synthesize speech with Microsoft's **MAI-Voice-1** voices via **Azure AI Speech REST API**.

## Status

Reworked to use `curl` + SSML instead of the Azure Speech Python SDK, which is much less annoying and much easier to publish.

## Files

- `scripts/speak.sh` — speech synthesis CLI
- `_meta.json` — publishing metadata

## Required environment variables

```bash
export AZURE_SPEECH_KEY="YOUR_SPEECH_RESOURCE_KEY"
export AZURE_SPEECH_REGION="eastus"
```

## How to get the API key and region

1. Open the Azure portal.
2. Find your **Speech** or **Foundry Speech** resource.
3. Open **Keys and Endpoint**.
4. Copy one of the keys.
5. Note the resource region, for example `eastus`.
6. Export them as `AZURE_SPEECH_KEY` and `AZURE_SPEECH_REGION`.

If the voice API refuses to cooperate, the first thing to check is whether your Speech resource is in a region that actually supports MAI-Voice preview.

Optional:

```bash
export AZURE_SPEECH_OUTPUT_FORMAT="audio-24khz-160kbitrate-mono-mp3"
```

## Examples

```bash
bash scripts/speak.sh --text "Hello Steve"
bash scripts/speak.sh --text "Hello Steve" --voice en-us-Iris:MAI-Voice-1 --out /tmp/iris.mp3
bash scripts/speak.sh --text-file /tmp/input.txt --voice en-us-June:MAI-Voice-1 --style empathy --out /tmp/june.mp3
bash scripts/speak.sh --list-voices
```

## Supported voices

- `en-us-Jasper:MAI-Voice-1`
- `en-us-June:MAI-Voice-1`
- `en-us-Grant:MAI-Voice-1`
- `en-us-Iris:MAI-Voice-1`
- `en-us-Reed:MAI-Voice-1`
- `en-us-Joy:MAI-Voice-1`

## Caveats

- Not yet live-tested against your Azure account in this session.
- This script relies on Azure Speech REST behavior and SSML support for MAI voices.
- Style support is optional and uses `mstts:express-as`.

## Publish

Suggested publish command:

```bash
clawhub publish ./skills/mai-voice --slug mai-voice --name "MAI Voice" --version 0.1.0 --changelog "Initial release: Azure Speech REST MAI-Voice-1 synthesis skill with selectable voices"
```


path: _meta.json
content: {
  "title": "MAI Voice",
  "slug": "mai-voice",
  "version": "0.1.0",
  "summary": "Synthesize speech with Microsoft's MAI-Voice-1 voices via Azure AI Speech.",
  "license": "MIT",
  "keywords": [
    "azure",
    "speech",
    "tts",
    "voice",
    "mai"
  ]
}


path: scripts/speak.sh
content: #!/usr/bin/env bash
set -euo pipefail

usage() {
  cat >&2 <<'EOF'
Usage:
  speak.sh --text "hello" [--voice en-us-Jasper:MAI-Voice-1] [--style excitement] [--out /tmp/out.mp3]
  speak.sh --text-file /path/to/input.txt [--voice ...] [--style ...] [--format audio-24khz-160kbitrate-mono-mp3]
  speak.sh --list-voices

Required env:
  AZURE_SPEECH_KEY
  AZURE_SPEECH_REGION

Optional env:
  AZURE_SPEECH_OUTPUT_FORMAT   (default: audio-24khz-160kbitrate-mono-mp3)
EOF
  exit 2
}

voices=(
  "en-us-Jasper:MAI-Voice-1"
  "en-us-June:MAI-Voice-1"
  "en-us-Grant:MAI-Voice-1"
  "en-us-Iris:MAI-Voice-1"
  "en-us-Reed:MAI-Voice-1"
  "en-us-Joy:MAI-Voice-1"
)

list_voices() {
  printf '%s\n' "${voices[@]}"
}

escape_xml() {
  sed -e 's/&/\&amp;/g' \
      -e 's/</\&lt;/g' \
      -e 's/>/\&gt;/g' \
      -e "s/'/\&apos;/g" \
      -e 's/"/\&quot;/g'
}

if [[ $# -eq 0 ]]; then
  usage
fi

text=""
text_file=""
voice="en-us-Jasper:MAI-Voice-1"
style=""
out="./mai-voice.mp3"
format="${AZURE_SPEECH_OUTPUT_FORMAT:-audio-24khz-160kbitrate-mono-mp3}"

while [[ $# -gt 0 ]]; do
  case "$1" in
    --text)
      text="${2:-}"
      shift 2
      ;;
    --text-file)
      text_file="${2:-}"
      shift 2
      ;;
    --voice)
      voice="${2:-}"
      shift 2
      ;;
    --style)
      style="${2:-}"
      shift 2
      ;;
    --out)
      out="${2:-}"
      shift 2
      ;;
    --format)
      format="${2:-}"
      shift 2
      ;;
    --list-voices)
      list_voices
      exit 0
      ;;
    -h|--help)
      usage
      ;;
    *)
      echo "Unknown arg: $1" >&2
      usage
      ;;
  esac
done

if [[ -z "${AZURE_SPEECH_KEY:-}" ]]; then
  echo "Missing AZURE_SPEECH_KEY" >&2
  exit 1
fi

if [[ -z "${AZURE_SPEECH_REGION:-}" ]]; then
  echo "Missing AZURE_SPEECH_REGION" >&2
  exit 1
fi

if [[ -n "$text" && -n "$text_file" ]]; then
  echo "Use either --text or --text-file, not both" >&2
  exit 1
fi

if [[ -z "$text" && -z "$text_file" ]]; then
  echo "Provide --text or --text-file" >&2
  exit 1
fi

if [[ -n "$text_file" ]]; then
  if [[ ! -f "$text_file" ]]; then
    echo "Text file not found: $text_file" >&2
    exit 1
  fi
  text="$(cat "$text_file")"
fi

voice_ok=0
for v in "${voices[@]}"; do
  if [[ "$voice" == "$v" ]]; then
    voice_ok=1
    break
  fi
done
if [[ "$voice_ok" -ne 1 ]]; then
  echo "Unknown voice: $voice" >&2
  echo "Supported voices:" >&2
  list_voices >&2
  exit 1
fi

mkdir -p "$(dirname "$out")"

escaped_text="$(printf '%s' "$text" | escape_xml)"
if [[ -n "$style" ]]; then
  escaped_style="$(printf '%s' "$style" | escape_xml)"
  body="<mstts:express-as style=\"${escaped_style}\">${escaped_text}</mstts:express-as>"
else
  body="${escaped_text}"
fi

ssml="<speak version='1.0' xmlns='http://www.w3.org/2001/10/synthesis' xmlns:mstts='http://www.w3.org/2001/mstts' xml:lang='en-US'><voice name='${voice}'>${body}</voice></speak>"

url="https://${AZURE_SPEECH_REGION}.tts.speech.microsoft.com/cognitiveservices/v1"

curl -sS --fail-with-body \
  -X POST "$url" \
  -H "Ocp-Apim-Subscription-Key: ${AZURE_SPEECH_KEY}" \
  -H "Content-Type: application/ssml+xml" \
  -H "X-Microsoft-OutputFormat: ${format}" \
  -H "User-Agent: curl" \
  --data-raw "$ssml" \
  --output "$out"

echo "$out"


path: test/test_basic.sh
content: #!/usr/bin/env bash
set -euo pipefail

out="$(bash "$(dirname "$0")/../scripts/speak.sh" --list-voices)"
printf '%s
' "$out" | grep -q 'en-us-Jasper:MAI-Voice-1'
printf '%s
' "$out" | grep -q 'en-us-Iris:MAI-Voice-1'
echo ok


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)