Voice Source/Output for Waken — file-drop speech-to-text in, text-to-speech out, via OpenAI's audio API.
Project description
waken-voice
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0e578c30e2d08b873024a72e4a95e5e47b6b498a6378aa8062a5a46fa8fb5c3e
|
|
| MD5 |
3dd523251b6e72d4862435ebaa3eaa08
|
|
| BLAKE2b-256 |
4aa895136718d2f947950a32bab5c5efa189620d48b403da9489cbbb1909aaf6
|
Provenance
The following attestation bundles were made for waken_voice-0.1.0.tar.gz:
Publisher:
publish.yml on WakenHQ/waken-voice
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
waken_voice-0.1.0.tar.gz -
Subject digest:
0e578c30e2d08b873024a72e4a95e5e47b6b498a6378aa8062a5a46fa8fb5c3e - Sigstore transparency entry: 2082077037
- Sigstore integration time:
-
Permalink:
WakenHQ/waken-voice@f78bb89eb4f6ef7ff1ea19685f99fe1b25634a80 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/WakenHQ
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f78bb89eb4f6ef7ff1ea19685f99fe1b25634a80 -
Trigger Event:
push
-
Statement type:
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
90e3dad6d3e8be91dac65834c0ee683793a4443b5f3cdde998c010a9be3632fc
|
|
| MD5 |
b8f3103336a45f165a34c01548dd3ae9
|
|
| BLAKE2b-256 |
894baee572583d926face86408c031de8d26efd3b6456b7ee7c8e10e1713a1f1
|
Provenance
The following attestation bundles were made for waken_voice-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on WakenHQ/waken-voice
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
waken_voice-0.1.0-py3-none-any.whl -
Subject digest:
90e3dad6d3e8be91dac65834c0ee683793a4443b5f3cdde998c010a9be3632fc - Sigstore transparency entry: 2082077047
- Sigstore integration time:
-
Permalink:
WakenHQ/waken-voice@f78bb89eb4f6ef7ff1ea19685f99fe1b25634a80 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/WakenHQ
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f78bb89eb4f6ef7ff1ea19685f99fe1b25634a80 -
Trigger Event:
push
-
Statement type: