Skill: teamtelnyx/telnyx-tts (version 1.0.0)

--- name: telnyx-tts description: Generate speech audio from text using Telnyx Text-to-Speech API. Use when you need to convert text to spoken audio, create voice messages, or generate audio content. metadata: {"openclaw":{"emoji":"🔊","requires":{"bins":["python3"],"env":["TELNYX_API_KEY"]},"primaryEnv":"TELNYX_API_KEY"}} --- # Telnyx Text-to-Speech Generate high-quality speech audio from text using the Telnyx TTS API. ## Usage To convert text to speech, run the script: ```bash {baseDir}/scripts/telnyx-tts.py "Your text here" -o /tmp/output.mp3 ``` The script outputs the path to the generated audio file on success. ## Options - `-o, --output PATH`: Output file path (default: output.mp3) - `--voice VOICE`: Voice ID (default: Telnyx.NaturalHD.astra) ## Available Voices Telnyx provides multiple voice options: - **Telnyx NaturalHD**: Premium voices with refined prosody - `Telnyx.NaturalHD.astra` (default) - `Telnyx.NaturalHD.luna` - `Telnyx.NaturalHD.andersen_johan` - **Telnyx KokoroTTS**: Budget-friendly for high-volume - `Telnyx.KokoroTTS.af` - `Telnyx.KokoroTTS.am` ## Example Generate speech and return as media: ```bash {baseDir}/scripts/telnyx-tts.py "Hello! This is a test of Telnyx text to speech." -o /tmp/tts-output.mp3 ``` Then return the audio file: ``` MEDIA: /tmp/tts-output.mp3 ``` For Telegram voice notes, the audio will be sent as a voice message. ## Environment Requires `TELNYX_API_KEY` environment variable to be set.

path: scripts/telnyx-tts.py
content: #!/usr/bin/env python3
"""
Telnyx Text-to-Speech CLI for OpenClaw.
Usage: telnyx-tts.py <text> [-o output.mp3] [--voice VOICE]
Requires: TELNYX_API_KEY environment variable

Uses Telnyx WebSocket TTS API:
wss://api.telnyx.com/v2/text-to-speech/speech

The API sends audio in two forms:
1. Streaming chunks (small 1KB frames with text=null) for real-time playback
2. Complete blob (entire audio with text=<original>) 
3. Final frame (isFinal=true)

We use only the streaming chunks to avoid duplication.
"""

import argparse
import asyncio
import base64
import json
import os
import sys

try:
    import websockets
except ImportError:
    print("Error: websockets library required. Install with: pip install websockets", file=sys.stderr)
    sys.exit(1)


async def text_to_speech(text: str, api_key: str, voice: str, output_path: str) -> bool:
    """Convert text to speech using Telnyx WebSocket TTS API."""

    url = f"wss://api.telnyx.com/v2/text-to-speech/speech?voice={voice}"
    headers = {
        "Authorization": f"Bearer {api_key}"
    }

    audio_chunks = []
    
    try:
        async with websockets.connect(url, additional_headers=headers) as ws:
            # Send initialization frame (required)
            await ws.send(json.dumps({"text": " "}))

            # Send text frame
            await ws.send(json.dumps({"text": text}))

            # Send stop frame
            await ws.send(json.dumps({"text": ""}))

            # Receive audio chunks
            while True:
                try:
                    response = await asyncio.wait_for(ws.recv(), timeout=30.0)
                    data = json.loads(response)

                    # Stop on final frame
                    if data.get("isFinal"):
                        break
                    
                    # Skip the complete blob (has text set to original input)
                    if data.get("text") is not None:
                        continue
                    
                    # Collect streaming chunks only
                    if "audio" in data and data["audio"]:
                        audio_chunk = base64.b64decode(data["audio"])
                        audio_chunks.append(audio_chunk)

                except asyncio.TimeoutError:
                    break
                except websockets.exceptions.ConnectionClosed:
                    break

    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        return False

    if not audio_chunks:
        print("Error: No audio received", file=sys.stderr)
        return False

    # Write streaming chunks only
    with open(output_path, "wb") as f:
        for chunk in audio_chunks:
            f.write(chunk)

    return True


def main():
    parser = argparse.ArgumentParser(description="Telnyx Text-to-Speech")
    parser.add_argument("text", help="Text to convert to speech")
    parser.add_argument("-o", "--output", default="output.mp3", help="Output file path (default: output.mp3)")
    parser.add_argument("--voice", default="Telnyx.NaturalHD.astra",
                       help="Voice ID (default: Telnyx.NaturalHD.astra)")

    args = parser.parse_args()

    [REDACTED_SECRET]"TELNYX_API_KEY")
    if not [REDACTED_SECRET]"Error: TELNYX_API_KEY environment variable not set", file=sys.stderr)
        sys.exit(1)

    success = asyncio.run(text_to_speech(args.text, api_key, args.voice, args.output))

    if success:
        print(args.output)
        sys.exit(0)
    else:
        sys.exit(1)


if __name__ == "__main__":
    main()


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