Skip to main content

Voice Source/Output for Waken — file-drop speech-to-text in, text-to-speech out, via OpenAI's audio API.

Project description

waken-voice

CI License: MIT

Voice Source and Output for Waken — "nginx for AI agents." Unlike waken-claude/waken-gemini/waken-copilot, this package doesn't wrap an AI backend at all: it wraps a channel. VoiceSource turns an audio file into an Event; VoiceOutput turns a Response back into audio. Both are backed by OpenAI's audio API (Whisper for speech-to-text, TTS for text-to-speech).

What this is NOT: a live microphone listener

Continuous microphone capture with voice-activity-detection to segment utterances is a real, hard, hardware/OS-dependent problem — and not one an autonomously-built package can honestly claim to have solved without a real microphone and a human speaking into it to verify against. So VoiceSource doesn't try. Instead it watches a directory for audio files appearing on disk, exactly like the built-in FilesystemSource watches for any file — dropped there by a phone system, a Telegram/Slack voice-message webhook, a push-to-talk recorder, or anything else. That's a small, honest, fully testable scope that composes cleanly with whatever actually captures audio, which is the same "small, composable pieces" philosophy Waken itself is built on.

Install

pip install waken-voice

Needs an OpenAI API key: set OPENAI_API_KEY in the environment (the default the underlying openai SDK reads), or pass api_key=... as a keyword argument to VoiceSource/VoiceOutput — both forward unrecognized keyword arguments straight to openai.AsyncOpenAI(...).

Usage

from waken import Runtime
from waken_openai import OpenAIAdapter
from waken_voice import VoiceSource, VoiceOutput

runtime = Runtime()
runtime.target("openai", OpenAIAdapter())
runtime.source("voice-in", VoiceSource(watch="./voice-inbox", target="openai"))
runtime.output("voice-in", VoiceOutput(output_dir="./voice-outbox"))
runtime.run()

Drop a .wav/.mp3/.m4a/.ogg file into ./voice-inbox; VoiceSource transcribes it and dispatches an Event(payload={"prompt": <transcript>}) to the "openai" target. runtime.output(name, ...) registers an Output under a name resolved by event.source (or an explicit event.output) — so registering VoiceOutput under "voice-in", the same name as the source above, means a Response to a voice-originated Event gets spoken back by default; see docs/api-spec.md §3 and §9 in the main waken repo for the full delivery-resolution rule.

VoiceSource

VoiceSource(
    watch,              # directory to poll for new audio files
    target,             # name of the registered Target to dispatch to
    interval=1.0,       # poll interval, seconds
    source_name="voice",
    model="whisper-1",  # OpenAI transcription model
    **client_kwargs,    # forwarded to openai.AsyncOpenAI(...)
)

Polls watch every interval seconds for new files, same mechanism as the built-in FilesystemSource (see waken/plugins/sources/filesystem.py) — no OS-level file-watching dependency, files present before start() are the baseline and never fire. Only .wav, .mp3, .m4a, and .ogg files are transcribed; anything else is ignored silently, since handing a non-audio file to the transcription API is a guaranteed, pointless error rather than a useful attempt.

VoiceOutput

VoiceOutput(
    output_dir,        # directory to write synthesized audio into
    voice="alloy",     # OpenAI TTS voice
    model="tts-1",     # OpenAI TTS model
    play=True,         # attempt local playback after writing the file
    **client_kwargs,   # forwarded to openai.AsyncOpenAI(...)
)

Writes {event.event_id}.mp3 under output_dir. A Response with no text delivers nothing.

Playback (play=True, the default) is best-effort and untested against real audio hardware or OS combinations. _play shells out to a platform player (afplay on macOS, paplay on Linux, an unverified fallback elsewhere) via asyncio.create_subprocess_exec, after the file is already safely written to disk — a missing or failing player is logged, not raised. This is the one piece of the package that genuinely can't be verified by an agent with no speakers to listen to; treat it as a starting point for your own environment, not a guarantee. Set play=False and hook your own playback (or upload/streaming path) onto the written file if you need something verified for your setup. (Same honest-about-limits spirit as waken-copilot's README regarding its own unverified pieces.)

Development

git clone https://github.com/WakenHQ/waken-voice
cd waken-voice
pip install -e ".[dev]"
pytest

Tests mock openai.AsyncOpenAI and VoiceOutput._play entirely — no real network access, API key, or audio hardware is required to run them.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

waken_voice-0.1.0.tar.gz (9.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

waken_voice-0.1.0-py3-none-any.whl (8.6 kB view details)

Uploaded Python 3

File details

Details for the file waken_voice-0.1.0.tar.gz.

File metadata

  • Download URL: waken_voice-0.1.0.tar.gz
  • Upload date:
  • Size: 9.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for waken_voice-0.1.0.tar.gz
Algorithm Hash digest
SHA256 0e578c30e2d08b873024a72e4a95e5e47b6b498a6378aa8062a5a46fa8fb5c3e
MD5 3dd523251b6e72d4862435ebaa3eaa08
BLAKE2b-256 4aa895136718d2f947950a32bab5c5efa189620d48b403da9489cbbb1909aaf6

See more details on using hashes here.

Provenance

The following attestation bundles were made for waken_voice-0.1.0.tar.gz:

Publisher: publish.yml on WakenHQ/waken-voice

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file waken_voice-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: waken_voice-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 8.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for waken_voice-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 90e3dad6d3e8be91dac65834c0ee683793a4443b5f3cdde998c010a9be3632fc
MD5 b8f3103336a45f165a34c01548dd3ae9
BLAKE2b-256 894baee572583d926face86408c031de8d26efd3b6456b7ee7c8e10e1713a1f1

See more details on using hashes here.

Provenance

The following attestation bundles were made for waken_voice-0.1.0-py3-none-any.whl:

Publisher: publish.yml on WakenHQ/waken-voice

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page