Skill: javier887/vibevoice (version 1.0.0)

--- name: vibevoice description: Local Spanish TTS using Microsoft VibeVoice. Generate natural voice audio from text, optimized for WhatsApp voice messages. metadata: author: estudiosdurero version: "1.0.0" homepage: https://github.com/microsoft/VibeVoice openclaw: emoji: "🎙️" requires: bins: ["ffmpeg", "python3"] env: [] install: - id: "vibevoice-clone" kind: "manual" label: "Clone VibeVoice repo and setup venv" instructions: | git clone https://github.com/microsoft/VibeVoice.git ~/VibeVoice cd ~/VibeVoice python3 -m venv venv source venv/bin/activate pip install -e . pip install torch torchaudio --- # VibeVoice TTS Local text-to-speech using Microsoft's VibeVoice model. Generates natural Spanish voice audio, perfect for WhatsApp voice messages. ## Quick Start ```bash # Basic usage {baseDir}/scripts/vv.sh "Hola, esto es una prueba" -o /tmp/audio.ogg # From file {baseDir}/scripts/vv.sh -f texto.txt -o /tmp/audio.ogg # Different voice {baseDir}/scripts/vv.sh "Texto" -v en-Wayne -o /tmp/audio.ogg # Adjust speed (0.5-2.0) {baseDir}/scripts/vv.sh "Texto" -s 1.2 -o /tmp/audio.ogg ``` ## Configuration | Setting | Default | Description | |---------|---------|-------------| | Voice | `sp-Spk1_man` | Spanish male voice (slight Mexican accent) | | Speed | `1.15` | 15% faster than normal | | Format | `.ogg` | Opus codec for WhatsApp | ## Available Voices Spanish: - `sp-Spk1_man` - Male, slight Mexican accent (default) English: - `en-Wayne` - Male - `en-Denise` - Female - Other voices in `~/VibeVoice/demo/voices/streaming_model/` ## Output Formats - `.ogg` - Opus codec (WhatsApp compatible, recommended) - `.mp3` - MP3 format - `.wav` - Uncompressed WAV ## For WhatsApp Always use `.ogg` format with `asVoice=true` in the message tool: ```bash # Generate {baseDir}/scripts/vv.sh "Tu mensaje aquí" -o /tmp/mensaje.ogg # Send via message tool message action=send channel=whatsapp to="+34XXXXXXXXX" filePath=/tmp/mensaje.ogg asVoice=true ``` ## Requirements - **GPU**: NVIDIA with ~2GB VRAM - **VibeVoice**: Installed at `~/VibeVoice` - **ffmpeg**: For audio conversion - **Python 3.10+**: With torch, torchaudio ## Performance - RTF: ~0.24x (generates faster than realtime) - 1 minute of audio ≈ 15 seconds to generate ## Notes - First run loads model (~10s), subsequent runs are faster - Audio rule: Only send voice if user requests it or speaks via audio - Keep text under 1500 chars for best quality

path: README.md
content: # VibeVoice TTS Skill

🎙️ Local Spanish text-to-speech for OpenClaw using Microsoft's VibeVoice model.

## Features

- **Natural Spanish voice** - High quality TTS with slight Mexican accent
- **WhatsApp optimized** - Outputs .ogg (Opus) for voice messages
- **Fast** - RTF ~0.24x (faster than realtime)
- **Local** - Runs on your GPU, no API costs
- **Configurable** - Multiple voices, adjustable speed

## Requirements

- NVIDIA GPU with ~2GB VRAM
- Python 3.10+
- ffmpeg
- [VibeVoice](https://github.com/microsoft/VibeVoice) installed at `~/VibeVoice`

## Installation

1. Install VibeVoice:
```bash
git clone https://github.com/microsoft/VibeVoice.git ~/VibeVoice
cd ~/VibeVoice
python3 -m venv venv
source venv/bin/activate
pip install -e .
pip install torch torchaudio
```

2. Install this skill:
```bash
clawhub install vibevoice
```

## Usage

```bash
# Basic
./scripts/vv.sh "Hola mundo" -o /tmp/audio.ogg

# With options
./scripts/vv.sh "Texto largo aquí" -v sp-Spk1_man -s 1.15 -o /tmp/audio.ogg
```

## Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `VIBEVOICE_DIR` | `~/VibeVoice` | Installation path |
| `VIBEVOICE_VOICE` | `sp-Spk1_man` | Default voice |
| `VIBEVOICE_SPEED` | `1.15` | Playback speed |

## Author

Created by [Estudios Durero](https://estudiosdurero.com) for internal use with OpenClaw.

## License

MIT


path: scripts/vv.sh
content: #!/usr/bin/env bash
# VibeVoice CLI - Local Spanish TTS
# Part of vibevoice skill for OpenClaw

set -e

VIBEVOICE_DIR="${VIBEVOICE_DIR:-$HOME/VibeVoice}"
VOICE="${VIBEVOICE_VOICE:-sp-Spk1_man}"
OUTPUT="/tmp/vibevoice_output.ogg"
SPEED="${VIBEVOICE_SPEED:-1.15}"
TEXT=""

# Parse args
while [[ $# -gt 0 ]]; do
    case $1 in
        -o|--output)
            OUTPUT="$2"
            shift 2
            ;;
        -v|--voice)
            VOICE="$2"
            shift 2
            ;;
        -f|--file)
            TEXT=$(cat "$2")
            shift 2
            ;;
        -s|--speed)
            SPEED="$2"
            shift 2
            ;;
        -h|--help)
            echo "VibeVoice CLI - Local Spanish TTS"
            echo ""
            echo "Usage: vv.sh \"text\" [-o output.ogg] [-v voice] [-s speed]"
            echo "       vv.sh -f file.txt [-o output.ogg]"
            echo ""
            echo "Options:"
            echo "  -o, --output   Output file (default: /tmp/vibevoice_output.ogg)"
            echo "  -v, --voice    Voice to use (default: sp-Spk1_man)"
            echo "  -s, --speed    Speech speed 0.5-2.0 (default: 1.15)"
            echo "  -f, --file     Read text from file"
            echo ""
            echo "Environment:"
            echo "  VIBEVOICE_DIR    VibeVoice install path (default: ~/VibeVoice)"
            echo "  VIBEVOICE_VOICE  Default voice"
            echo "  VIBEVOICE_SPEED  Default speed"
            echo ""
            echo "Available voices:"
            ls "$VIBEVOICE_DIR/demo/voices/streaming_model/"*.pt 2>/dev/null | xargs -n1 basename | sed 's/.pt$//' || echo "  (install VibeVoice first)"
            exit 0
            ;;
        *)
            TEXT="$1"
            shift
            ;;
    esac
done

if [ -z "$TEXT" ]; then
    echo "Error: No text provided" >&2
    echo "Usage: vv.sh \"text\" [-o output.ogg]" >&2
    exit 1
fi

if [ ! -d "$VIBEVOICE_DIR" ]; then
    echo "Error: VibeVoice not found at $VIBEVOICE_DIR" >&2
    echo "Install: git clone https://github.com/microsoft/VibeVoice.git ~/VibeVoice" >&2
    exit 1
fi

# Temp files
TEMP_TEXT=$(mktemp /tmp/vibevoice_text_XXXXXX.txt)
TEMP_WAV=$(mktemp /tmp/vibevoice_wav_XXXXXX.wav)
trap "rm -f '$TEMP_TEXT' '$TEMP_WAV'" EXIT

echo "$TEXT" > "$TEMP_TEXT"

# Generate audio
cd "$VIBEVOICE_DIR"
source venv/bin/activate

python3 << PYEOF
import torch
import sys
import warnings
warnings.filterwarnings("ignore")

text = open("$TEMP_TEXT").read().strip()
output_wav = "$TEMP_WAV"
voice = "$VOICE"

from vibevoice.modular.modeling_vibevoice_streaming_inference import VibeVoiceStreamingForConditionalGenerationInference
from vibevoice.processor.vibevoice_streaming_processor import VibeVoiceStreamingProcessor

model_path = "microsoft/VibeVoice-Realtime-0.5B"
processor = VibeVoiceStreamingProcessor.from_pretrained(model_path)

model = VibeVoiceStreamingForConditionalGenerationInference.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    device_map="cuda",
    attn_implementation="sdpa",
)
model.eval()
model.set_ddpm_inference_steps(num_steps=5)

voice_path = f"$VIBEVOICE_DIR/demo/voices/streaming_model/{voice}.pt"
all_prefilled_outputs = torch.load(voice_path, map_location="cuda", weights_only=False)

inputs = processor.process_input_with_cached_prompt(
    text=text,
    cached_prompt=all_prefilled_outputs,
    padding=True,
    return_tensors="pt",
    return_attention_mask=True,
)

for k, v in inputs.items():
    if torch.is_tensor(v):
        inputs[k] = v.to("cuda")

import copy
outputs = model.generate(
    **inputs,
    max_new_tokens=None,
    cfg_scale=1.5,
    tokenizer=processor.tokenizer,
    generation_config={'do_sample': False},
    verbose=False,
    all_prefilled_outputs=copy.deepcopy(all_prefilled_outputs),
)

processor.save_audio(outputs.speech_outputs[0], output_path=output_wav)

audio_samples = outputs.speech_outputs[0].shape[-1]
duration = audio_samples / 24000
print(f"Generated {duration:.1f}s of audio", file=sys.stderr)
PYEOF

# Convert to output format with speed adjustment
if [[ "$OUTPUT" == *.ogg ]]; then
    ffmpeg -y -i "$TEMP_WAV" -af "atempo=$SPEED" -c:a libopus -b:a 64k "$OUTPUT" 2>/dev/null
elif [[ "$OUTPUT" == *.mp3 ]]; then
    ffmpeg -y -i "$TEMP_WAV" -af "atempo=$SPEED" -c:a libmp3lame -b:a 128k "$OUTPUT" 2>/dev/null
else
    ffmpeg -y -i "$TEMP_WAV" -af "atempo=$SPEED" "$OUTPUT" 2>/dev/null
fi

echo "MEDIA: $OUTPUT"


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