npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@shinshin86/sayx

v0.1.1

Published

Text-to-speech CLI tool powered by @aituber-onair/voice

Downloads

88

Readme

sayx

Logo

Text-to-speech CLI tool powered by @aituber-onair/voice.

Quick Start

Using npx (no install required)

npx @shinshin86/sayx こんにちは

By default, sayx uses the built-in config (if no config file exists):

  • Engine: voicevox
  • Speaker: 1 (VOICEVOX speaker ID)
  • Preset: default

This means VOICEVOX must be running locally at http://127.0.0.1:50021 for the quick start to work. If you want to use a cloud engine (e.g. OpenAI), set up an API key and pass --engine openai.

Global Install

npm install -g @shinshin86/sayx
sayx こんにちは

Local Install

npm install @shinshin86/sayx

Local Development

git clone <repository>
cd sayx
npm install
npm run build
node dist/cli.js こんにちは

Requirements

  • Node.js 20+
  • Audio player installed on your system (e.g., afplay on macOS, aplay on Linux, or media player on Windows)
  • A voice engine running (see Supported Engines)

Usage

Basic Usage

# Speak text
sayx こんにちは

# Multiple words are joined with spaces
sayx こんにちは 世界

# Read from stdin
echo "Hello, world!" | sayx
cat message.txt | sayx

Options

sayx [options] [text...]

Options:
  -e, --engine <engineType>  Override engine type
  -s, --speaker <speaker>    Override speaker
  -p, --preset <presetName>  Select preset (default: default)
  --config <path>            Specify config file path
  --out <file>               Save audio to file
  --no-play                  Do not play audio (file output only)
  -V, --version              Output version number
  -h, --help                 Display help

Examples

# Save to file
sayx "Hello" --out hello.wav

# Save to a specific path without extension (auto-detected extension is appended)
sayx "Hello" --out ./output/hello

# Save without playing
sayx "Hello" --out hello.wav --no-play

# Use OpenAI TTS
sayx "Hello" --engine openai --speaker alloy

# Use a preset
sayx "Hello" --preset narrator

For AI Agents

sayx is designed for command-based automation, so agents can chain small CLI actions safely.

Recommended Agent Flow

  1. Run health checks first:
    sayx doctor
  2. Fetch available voices for the target engine:
    sayx list voices --engine aivisSpeech
  3. Speak with an explicit speaker ID:
    sayx "Hello from agent" --engine aivisSpeech --speaker 888753760

Example: Random AivisSpeech Voice (2-step)

# Step 1: get one random speaker id from `list voices`
VOICE_ID=$(sayx list voices --engine aivisSpeech \
  | awk '/^[[:space:]]+[0-9]+:/{gsub(":", "", $1); print $1}' \
  | awk 'BEGIN{srand()} {a[NR]=$1} END{if(NR>0) print a[int(rand()*NR)+1]}')

# Step 2: speak with the selected speaker
sayx "Hello from random AivisSpeech voice" --engine aivisSpeech --speaker "$VOICE_ID"

Headless / CI Usage

Use file output mode when running in non-interactive environments:

sayx "CI speech test" --engine aivisSpeech --speaker 888753760 --out ./out/sample --no-play

Exit Codes for Automation

  • 0: success (including supported empty voice list and unsupported voice-list engines)
  • 1: command failure (invalid options, missing config/API key, engine connection failure, voice list unreachable, synthesis failure)

Commands

Main commands and what they do:

  • sayx init: Creates a default config file. Config path: macOS/Linux: ~/.config/sayx/config.yaml Windows: %APPDATA%\sayx\config.yaml
  • sayx config path: Shows the config file path currently in use.
  • sayx list engines: Lists supported engine types.
  • sayx list voices / sayx list voices --engine openai: Lists available voices for an engine (engine-dependent; may be unsupported).
  • sayx list presets: Lists preset names defined in config.
  • sayx list presets --verbose: Shows detailed preset settings (speakOptions / engineOverrides).
  • sayx list presets --json: Outputs presets in JSON format.
  • sayx doctor: Diagnoses engine availability, API key readiness, and voice-list support.
  • sayx doctor --verbose: Includes detailed voice entries when available.
  • sayx bench ...: Runs benchmark jobs across engine/preset combinations and generates reports.

Benchmark (Compare Engines/Presets)

Examples:

# Basic usage - uses default engine and preset
sayx bench "Hello, world!"

# Compare multiple engines
sayx bench "Hello" --engines voicevox,openai

# Compare multiple presets
sayx bench "Hello" --presets default,narrator

# Full matrix: multiple engines x multiple presets
sayx bench "Hello" --engines voicevox,openai --presets default,narrator

# Specify output directory
sayx bench "Hello" --outdir ./my-bench-results

# Open report in browser after generation
sayx bench "Hello" --open

# JSON only (skip HTML generation)
sayx bench "Hello" --no-html

# Control parallelism
sayx bench "Hello" --concurrency 4

Bench Output

By default, benchmark results are saved to ./sayx-bench-YYYYMMDD-HHMMSS/:

sayx-bench-20240115-143022/
├── index.html           # Interactive HTML report
├── report.json          # Machine-readable results
├── resolved-config.json # Configuration used for this run
└── samples/
    ├── voicevox/
    │   └── default.wav
    └── openai/
        └── default.mp3

Viewing the Report

Open index.html directly in your browser. If audio doesn't play due to browser security restrictions, run a local server:

# Using npx
npx serve ./sayx-bench-20240115-143022

# Or Python
python -m http.server 8000 -d ./sayx-bench-20240115-143022

Then open http://localhost:3000/index.html (or port 8000 for Python).

Bench Options

| Option | Description | Default | |--------|-------------|---------| | --outdir <dir> | Output directory | ./sayx-bench-YYYYMMDD-HHMMSS | | --engines <list> | Comma-separated engines | Config default engine | | --presets <list> | Comma-separated presets | default preset | | --concurrency <n> | Parallel jobs | 2 | | --open | Open report in browser | No | | --no-html | Skip HTML, JSON only | Generate both | | --config <path> | Config file path | Default location | | -s, --speaker | Override speaker | From config/preset |

Output File Behavior

  • --out <path> saves synthesized audio to the target path.
  • If <path> has no extension, sayx detects the generated format and appends the extension automatically.
  • Use --no-play if you want file output only.

Configuration

Config file uses YAML format. Run sayx init to create a default config.

For local engines (voicevox, voicepeak, aivisSpeech), if API URL is not set in config, sayx falls back to default local endpoints:

  • voicevox: http://127.0.0.1:50021
  • voicepeak: http://127.0.0.1:20202
  • aivisSpeech: http://127.0.0.1:10101

Example Config

default:
  engineType: voicevox
  speaker: "1"
  apiKeyEnv: OPENAI_API_KEY
  voicevoxApiUrl: http://127.0.0.1:50021

presets:
  default:
    speakOptions: {}
    engineOverrides:
      voicevox:
        speaker: "1"
      openai:
        speaker: alloy
        model: tts-1

  narrator:
    speakOptions:
      speed: 0.9
    engineOverrides:
      openai:
        speaker: onyx
        model: tts-1-hd
      voicevox:
        speaker: "3"
        speedScale: 0.95

Config Priority

Options are resolved in this order (higher priority first):

  1. CLI options (--engine, --speaker, etc.)
  2. Preset settings
  3. Config default settings
  4. Built-in defaults

API Keys

API keys are resolved from config only (no automatic env var discovery). Only these engines require API keys: openai, aivisCloud, minimax. Local engines like voicevox, voicepeak, and aivisSpeech do not require an API key.

  1. Config file:

    default:
      apiKey: "sk-..."  # Avoid storing secrets in config
  2. Config + environment variable:

    default:
      apiKeyEnv: OPENAI_API_KEY
    export OPENAI_API_KEY=sk-...

Supported Engines

| Engine | Description | Requirements | |--------|-------------|--------------| | voicevox | Local Japanese TTS | VOICEVOX running | | voicepeak | VOICEPEAK TTS | VOICEPEAK API server | | openai | OpenAI TTS API | apiKey or apiKeyEnv | | aivisSpeech | AIVIS Speech (local) | AIVIS Speech server | | aivisCloud | AIVIS Cloud API | apiKey or apiKeyEnv | | minimax | MiniMax TTS API | apiKey or apiKeyEnv |

Troubleshooting

"VOICEVOX is not running"

VOICEVOX engine must be running locally. Download from voicevox.hiroshiba.jp and start the application.

Default URL: http://127.0.0.1:50021

"No API key found"

Set apiKey or apiKeyEnv in your config file:

default:
  apiKeyEnv: OPENAI_API_KEY
export OPENAI_API_KEY=sk-...

"Playback failed"

Ensure you have an audio player installed:

  • macOS: afplay (pre-installed)
  • Linux: Install aplay (ALSA), mpg123, or sox
  • Windows: Should work with default media player

If playback fails, the audio file is saved to a temp location (path shown in error message).

"No text provided"

Provide text as arguments or via stdin:

sayx "Hello"
echo "Hello" | sayx

"Voice listing is currently unavailable"

For local engines, this usually means the endpoint is not reachable.

sayx doctor
sayx list voices --engine aivisSpeech

Bench: Audio doesn't play in browser

Browsers block local file access for security. Use a local server:

npx serve ./sayx-bench-*

License

MIT