Skip to main content

🎙️ VoiSona Talk Proxy

A tiny proxy that makes local VoiSona Talk speech synthesis available over the network.

NOTE: This is an unofficial project and is not affiliated with, endorsed by, or supported by the maker of VoiSona Talk. Please do not contact them for support about this package.

💎 Features

  • 🌐 Access VoiSona Talk speech synthesis from other machines over the network
  • ⚡️ Respond faster by reusing cached audio for repeated requests
  • 🐍 Provide Python client for direct local use

📦 Installation

Requirements:

  • Python 3.11+
  • VoiSona Talk running locally
  • Local VoiSona Talk API available at http://127.0.0.1:32766/api/talk/v1

Install:

pip install voisona-talk-proxy

🚀 Quick Start

Start the proxy server:

voisona-talk-proxy --host 0.0.0.0 --port 32777

Underscore command and Python module forms are also available:

voisona_talk_proxy --host 0.0.0.0 --port 32777
python -m voisona_talk_proxy --host 0.0.0.0 --port 32777

Synthesize speech:

curl -u your-voisona-talk-user:your-voisona-talk-password \
  -X POST http://127.0.0.1:32777/speech-syntheses \
  -H "Content-Type: application/json" \
  -o output.wav \
  -d '{
    "text": "こんにちは",
    "language": "ja_JP",
    "voice_name": "tanaka-san_ja_JP"
  }'

Or open the browser playground: http://127.0.0.1:32777/playground/

The playground can load installed voices, synthesize text, preview the generated audio, and download the WAV file.

You can also mount the proxy inside your own FastAPI app:

from fastapi import FastAPI
from voisona_talk_proxy.proxy import VoisonaProxy

app = FastAPI()
proxy = VoisonaProxy(
    # username="your-voisona-talk-user",
    # password="your-voisona-talk-password",
)
app.include_router(proxy.get_api_router())

🧩 API Usage

Routes:

  • GET /voices
  • POST /speech-syntheses
  • DELETE /cache
  • DELETE /cache/{voice_name}
  • GET /health
  • GET /playground/
  • compatible /api/talk/v1/... paths for API routes above, except /playground/

NOTE: See the official VoiSona Talk API manual for request payload details.

GET /playground/

Opens a small browser page for testing speech synthesis, previewing audio, and downloading WAV files.

GET /voices

Returns installed voice libraries from the local VoiSona Talk API.

curl http://127.0.0.1:32777/voices

Example shape:

{
  "items": [
    {
      "voice_name": "tanaka-san_ja_JP",
      "voice_version": "2.0.1",
      "languages": ["ja_JP"]
    }
  ]
}

POST /speech-syntheses

Synthesizes speech and returns audio/wav.

Minimal request:

curl -X POST http://127.0.0.1:32777/speech-syntheses \
  -H "Content-Type: application/json" \
  -o output.wav \
  -d '{
    "text": "Hello!",
    "language": "ja_JP",
    "voice_name": "tanaka-san_ja_JP"
  }'

Credentials can be sent with HTTP Basic auth. In Swagger UI, use Authorize and enter your VoiSona username and password.

curl -u your-voisona-talk-user:your-voisona-talk-password \
  -X POST http://127.0.0.1:32777/speech-syntheses \
  -H "Content-Type: application/json" \
  -o output.wav \
  -d '{
    "text": "Hello!",
    "language": "ja_JP",
    "voice_name": "tanaka-san_ja_JP"
  }'

If HTTP Basic auth is omitted, the proxy falls back to credentials configured at startup with --username / --password or VOISONA_USERNAME / VOISONA_PASSWORD.

Request schema:

Field Type Required Notes
language string Yes Language code from the selected voice library, for example ja_JP.
text string Conditional Text to synthesize. Required unless non-empty analyzed_text is set. Max length: 500.
analyzed_text string Conditional Analyzed text generated by text analysis. If non-empty, text is ignored for synthesis. Max length: 50000.
voice_name string No Voice library name.
voice_version string No Voice library version.
global_parameters object No Global voice parameters such as speed, pitch, intonation, volume, huskiness, alp, and style_weights.
phoneme_durations number[] No Requested phoneme durations in seconds. Negative values mean automatic.

The proxy also accepts additional VoiSona request fields for compatibility. destination, output_file_path, force_enqueue, and can_overwrite_file are ignored by the proxy and sent upstream as proxy-managed values: destination="file", output_file_path=<cache path>, force_enqueue=true, and can_overwrite_file=true.

Full request example with /voices values and global_parameters:

import httpx

base_url = "http://127.0.0.1:32777"

voices = httpx.get(f"{base_url}/voices").json()
voice = voices["items"][0]

payload = {
    "text": "こんにちは",
    "language": voice["languages"][0],
    "voice_name": voice["voice_name"],
    "voice_version": voice["voice_version"],
    "global_parameters": {
        "alp": 0.0,
        "huskiness": 0.0,
        "intonation": 1.0,
        "pitch": 0.0,
        "speed": 2.0,
        "style_weights": [],
        "volume": 0.0,
    },
}

audio = httpx.post(f"{base_url}/speech-syntheses", json=payload).content

with open("output.wav", "wb") as f:
    f.write(audio)

GET /health

Returns a simple health check response.

curl http://127.0.0.1:32777/health
{"status": "ok"}

DELETE /cache

Clears cached audio for the default voice cache.

curl -X DELETE http://127.0.0.1:32777/cache
{"cleared": true, "voice_name": "default"}

You can also clear one voice cache by path or query parameter:

curl -X DELETE http://127.0.0.1:32777/cache/tanaka-san_ja_JP
curl -X DELETE "http://127.0.0.1:32777/cache?voice_name=tanaka-san_ja_JP"

🍪 Cache

The proxy caches generated audio under voisona_talk_cache/<voice_name>/<cache_key>.wav.

If voice_name is missing, the cache goes under default.

Set the proxy cache directory with --cache-dir:

voisona-talk-proxy --host 0.0.0.0 --port 32777 --cache-dir /path/to/cache

Or use VOISONA_CACHE_DIR:

export VOISONA_CACHE_DIR=/path/to/cache
voisona-talk-proxy --host 0.0.0.0 --port 32777

When mounting the proxy in your own FastAPI app, pass cache_dir to VoisonaProxy:

from fastapi import FastAPI
from voisona_talk_proxy.proxy import VoisonaProxy

app = FastAPI()
proxy = VoisonaProxy(
    # username="your-voisona-talk-user",
    # password="your-voisona-talk-password",
    cache_dir="/path/to/cache",
)
app.include_router(proxy.get_api_router())

⚙️ Configurations

CLI arguments take precedence over environment variables.

Setting CLI argument Environment variable Default
Listen host --host - 127.0.0.1
Listen port --port - 32777
VoiSona Talk API URL --voisona-url VOISONA_BASE_URL http://127.0.0.1:32766/api/talk/v1
Username --username VOISONA_USERNAME -
Password --password VOISONA_PASSWORD -
Cache directory --cache-dir VOISONA_CACHE_DIR voisona_talk_cache
Log level --log-level VOISONA_LOG_LEVEL info

Example:

export VOISONA_BASE_URL=http://127.0.0.1:32766/api/talk/v1
export VOISONA_USERNAME=your-voisona-talk-user
export VOISONA_PASSWORD=your-voisona-talk-password
export VOISONA_CACHE_DIR=/path/to/cache
export VOISONA_LOG_LEVEL=debug

voisona-talk-proxy --host 0.0.0.0 --port 32777

If VOISONA_USERNAME and VOISONA_PASSWORD are set, or --username and --password are passed, the proxy uses those credentials for requests that do not include HTTP Basic auth. In that mode, clients do not need to send credentials on every request.

NOTE: For more advanced FastAPI or Uvicorn settings, create your own main program and mount VoisonaProxy there.

🐍 Python Local Mode

from voisona_talk_proxy.client import VoisonaTalkClient

client = VoisonaTalkClient(
    base_url="http://127.0.0.1:32766/api/talk/v1",
)

audio = await client.synthesize({
    "text": "Hello!",
    "language": "ja_JP",
    "voice_name": "tanaka-san_ja_JP",
})

with open("output.wav", "wb") as f:
    f.write(audio)

await client.close()

You can also use get_voices() and pass values from an installed voice library. This is useful when you want to choose voices dynamically.

voices = await client.get_voices()
voice = voices["items"][0]

audio = await client.synthesize({
    "text": "Hello!",
    "language": voice["languages"][0],
    "voice_name": voice["voice_name"],
    "voice_version": voice["voice_version"],
})

Per-request credentials can also be passed as method arguments:

voices = await client.get_voices(username="user", password="pass")
audio = await client.synthesize(payload, username="user", password="pass")

🧪 Tests

The tests use the real local VoiSona Talk API, not mocks. Put your local API URL and credentials in pytest.ini, then run:

python -m pytest tests/

🌧️ Thanks

We built this repository to make 🌧️ 雨衣 / Ui's voice easier to use in all kinds of scenes. Thank you for the wonderful voice! ✨🙏✨

⚖️ License

MIT. Use it freely, and please share what you create with it on SNS!

Metadata

Release files for voisona-talk-proxy 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for voisona-talk-proxy 0.2.0
File Size Uploaded Provenance
voisona_talk_proxy-0.2.0.tar.gz 18.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for voisona-talk-proxy 0.2.0
File Interpreter ABI Platform
voisona_talk_proxy-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 35.4 kB

Release files / voisona_talk_proxy-0.2.0.tar.gz

Download URL voisona_talk_proxy-0.2.0.tar.gz
Size 18.2 kB
Tags Source
SHA-256 checksum
How to use checksums
994f6d496f2a374996b0163cfae0a59bcbb43c1465aa9a294b3fefd54bdc4bfd
BLAKE2b-256 checksum
How to use checksums
24a9a7611618f78b650ee8d481f19f785b37f3949e6a894d8f83c81f19da7b37
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release files / voisona_talk_proxy-0.2.0-py3-none-any.whl

Download URL voisona_talk_proxy-0.2.0-py3-none-any.whl
Size 17.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4d4ecc06f7ed000b885346db12b4d923cf1d6c85b7eb52abc2c19d77d3b16dac
BLAKE2b-256 checksum
How to use checksums
e10271305bd29415ae8a282eed3a0452073c84fe6417c2a6af9e7081a186aa69
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Security for voisona-talk-proxy 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page