hotato 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hotato-0.1.0/LICENSE +21 -0
- hotato-0.1.0/PKG-INFO +257 -0
- hotato-0.1.0/README.md +214 -0
- hotato-0.1.0/pyproject.toml +75 -0
- hotato-0.1.0/setup.cfg +4 -0
- hotato-0.1.0/src/hotato/__init__.py +33 -0
- hotato-0.1.0/src/hotato/_engine/__init__.py +47 -0
- hotato-0.1.0/src/hotato/_engine/__main__.py +131 -0
- hotato-0.1.0/src/hotato/_engine/audio.py +149 -0
- hotato-0.1.0/src/hotato/_engine/batch.py +160 -0
- hotato-0.1.0/src/hotato/_engine/score.py +358 -0
- hotato-0.1.0/src/hotato/_engine/vad.py +224 -0
- hotato-0.1.0/src/hotato/_stats.py +47 -0
- hotato-0.1.0/src/hotato/aggregate.py +346 -0
- hotato-0.1.0/src/hotato/benchmark.py +627 -0
- hotato-0.1.0/src/hotato/capture.py +615 -0
- hotato-0.1.0/src/hotato/cli.py +897 -0
- hotato-0.1.0/src/hotato/core.py +537 -0
- hotato-0.1.0/src/hotato/data/audio/01-hard-interruption.example.wav +0 -0
- hotato-0.1.0/src/hotato/data/audio/02-backchannel-mhm.example.wav +0 -0
- hotato-0.1.0/src/hotato/data/audio/03-filler-start.example.wav +0 -0
- hotato-0.1.0/src/hotato/data/audio/04-correction.example.wav +0 -0
- hotato-0.1.0/src/hotato/data/audio/05-telephony-8khz.example.wav +0 -0
- hotato-0.1.0/src/hotato/data/audio/06-double-talk.example.wav +0 -0
- hotato-0.1.0/src/hotato/data/audio/07-echo-bleed.example.wav +0 -0
- hotato-0.1.0/src/hotato/data/audio/08-rapid-turn-taking.example.wav +0 -0
- hotato-0.1.0/src/hotato/data/scenarios/01-hard-interruption.json +26 -0
- hotato-0.1.0/src/hotato/data/scenarios/02-backchannel-mhm.json +26 -0
- hotato-0.1.0/src/hotato/data/scenarios/03-filler-start.json +26 -0
- hotato-0.1.0/src/hotato/data/scenarios/04-correction.json +26 -0
- hotato-0.1.0/src/hotato/data/scenarios/05-telephony-8khz.json +26 -0
- hotato-0.1.0/src/hotato/data/scenarios/06-double-talk.json +26 -0
- hotato-0.1.0/src/hotato/data/scenarios/07-echo-bleed.json +29 -0
- hotato-0.1.0/src/hotato/data/scenarios/08-rapid-turn-taking.json +27 -0
- hotato-0.1.0/src/hotato/data/scenarios/manifest.json +76 -0
- hotato-0.1.0/src/hotato/export.py +204 -0
- hotato-0.1.0/src/hotato/fixmap.py +332 -0
- hotato-0.1.0/src/hotato/mcp_server.py +181 -0
- hotato-0.1.0/src/hotato/neural.py +101 -0
- hotato-0.1.0/src/hotato/pytest_plugin.py +127 -0
- hotato-0.1.0/src/hotato/report.py +1214 -0
- hotato-0.1.0/src/hotato/schema/envelope.v1.json +170 -0
- hotato-0.1.0/src/hotato/stackbench.py +534 -0
- hotato-0.1.0/src/hotato.egg-info/PKG-INFO +257 -0
- hotato-0.1.0/src/hotato.egg-info/SOURCES.txt +73 -0
- hotato-0.1.0/src/hotato.egg-info/dependency_links.txt +1 -0
- hotato-0.1.0/src/hotato.egg-info/entry_points.txt +6 -0
- hotato-0.1.0/src/hotato.egg-info/requires.txt +32 -0
- hotato-0.1.0/src/hotato.egg-info/top_level.txt +1 -0
- hotato-0.1.0/tests/test_backend.py +245 -0
- hotato-0.1.0/tests/test_benchmark.py +225 -0
- hotato-0.1.0/tests/test_capture.py +162 -0
- hotato-0.1.0/tests/test_cli.py +78 -0
- hotato-0.1.0/tests/test_core.py +124 -0
- hotato-0.1.0/tests/test_corpus_suites.py +377 -0
- hotato-0.1.0/tests/test_corpus_validate.py +145 -0
- hotato-0.1.0/tests/test_engine_parity.py +82 -0
- hotato-0.1.0/tests/test_examples_backchannel.py +66 -0
- hotato-0.1.0/tests/test_examples_funnel.py +79 -0
- hotato-0.1.0/tests/test_examples_latency.py +143 -0
- hotato-0.1.0/tests/test_export.py +131 -0
- hotato-0.1.0/tests/test_fixmap.py +184 -0
- hotato-0.1.0/tests/test_frozen_regression.py +43 -0
- hotato-0.1.0/tests/test_hostile_inputs.py +171 -0
- hotato-0.1.0/tests/test_mcp_parity.py +44 -0
- hotato-0.1.0/tests/test_mcp_report_path.py +56 -0
- hotato-0.1.0/tests/test_pr_comment.py +79 -0
- hotato-0.1.0/tests/test_pytest_plugin.py +114 -0
- hotato-0.1.0/tests/test_report.py +154 -0
- hotato-0.1.0/tests/test_report_analytics.py +218 -0
- hotato-0.1.0/tests/test_saa_card.py +58 -0
- hotato-0.1.0/tests/test_schema.py +99 -0
- hotato-0.1.0/tests/test_signals.py +306 -0
- hotato-0.1.0/tests/test_stackbench.py +332 -0
- hotato-0.1.0/tests/test_team.py +187 -0
hotato-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Attention Labs, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
hotato-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hotato
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Hotato: the open turn-taking eval for voice agents. Does your agent drop the turn, or hog it? Score barge-in / talk-over / backchannel / endpointing from a call recording, offline, with an honest fix map. MIT.
|
|
5
|
+
Author: Attention Labs, Inc.
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/attenlabs/hotato
|
|
8
|
+
Project-URL: Homepage, https://hotato.dev
|
|
9
|
+
Project-URL: Open engine (upstream), https://github.com/quantumCF/voice-agent-barge-in-tests
|
|
10
|
+
Keywords: hotato,voice-ai,voice-agents,evals,barge-in,turn-taking,mcp,agent-native,observability,reliability,livekit,pipecat,vapi
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
|
|
14
|
+
Classifier: Topic :: Software Development :: Testing
|
|
15
|
+
Requires-Python: >=3.9
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Provides-Extra: mcp
|
|
19
|
+
Requires-Dist: mcp>=1.2.0; extra == "mcp"
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
22
|
+
Requires-Dist: jsonschema>=4; extra == "dev"
|
|
23
|
+
Provides-Extra: vapi
|
|
24
|
+
Provides-Extra: twilio
|
|
25
|
+
Provides-Extra: livekit
|
|
26
|
+
Requires-Dist: livekit; extra == "livekit"
|
|
27
|
+
Requires-Dist: livekit-agents; extra == "livekit"
|
|
28
|
+
Provides-Extra: pipecat
|
|
29
|
+
Requires-Dist: pipecat-ai; extra == "pipecat"
|
|
30
|
+
Provides-Extra: neural
|
|
31
|
+
Requires-Dist: silero-vad>=5; extra == "neural"
|
|
32
|
+
Requires-Dist: onnxruntime>=1.16; extra == "neural"
|
|
33
|
+
Requires-Dist: numpy>=1.21; extra == "neural"
|
|
34
|
+
Provides-Extra: all
|
|
35
|
+
Requires-Dist: mcp>=1.2.0; extra == "all"
|
|
36
|
+
Requires-Dist: livekit; extra == "all"
|
|
37
|
+
Requires-Dist: livekit-agents; extra == "all"
|
|
38
|
+
Requires-Dist: pipecat-ai; extra == "all"
|
|
39
|
+
Requires-Dist: silero-vad>=5; extra == "all"
|
|
40
|
+
Requires-Dist: onnxruntime>=1.16; extra == "all"
|
|
41
|
+
Requires-Dist: numpy>=1.21; extra == "all"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
<p align="center">
|
|
45
|
+
<a href="https://hotato.dev">
|
|
46
|
+
<img src=".github/banner.png" alt="hotato: the open, offline turn-taking eval for voice agents" width="840">
|
|
47
|
+
</a>
|
|
48
|
+
</p>
|
|
49
|
+
|
|
50
|
+
<h1 align="center">
|
|
51
|
+
<img src="docs/assets/mascot.svg" alt="" width="26" align="top"> hotato
|
|
52
|
+
</h1>
|
|
53
|
+
|
|
54
|
+
<p align="center"><b>An open, offline tool that scores voice-agent turn-taking from a call recording.</b></p>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
58
|
+
<img alt="Python 3.9 to 3.13" src="https://img.shields.io/badge/python-3.9%20to%203.13-blue.svg">
|
|
59
|
+
<img alt="tests: passing" src="https://img.shields.io/badge/tests-passing-brightgreen.svg">
|
|
60
|
+
<img alt="build: passing" src="https://img.shields.io/badge/build-passing-brightgreen.svg">
|
|
61
|
+
<a href="https://hotato.dev"><img alt="site: hotato.dev" src="https://img.shields.io/badge/site-hotato.dev-e2470f.svg"></a>
|
|
62
|
+
</p>
|
|
63
|
+
|
|
64
|
+
<p align="center">
|
|
65
|
+
Built for anyone shipping voice agents on LiveKit, Pipecat, Vapi, Retell, or Twilio.<br>
|
|
66
|
+
Runs on your machine, so your call audio stays with you.
|
|
67
|
+
</p>
|
|
68
|
+
|
|
69
|
+
Point it at one of your own call recordings. It shows where your agent talked over
|
|
70
|
+
the caller, or missed a real interruption, and points each failure at the config
|
|
71
|
+
knob that fixes it. Every result is reproducible timing you can verify frame by
|
|
72
|
+
frame and gate a PR on.
|
|
73
|
+
|
|
74
|
+
## Quickstart (60 seconds)
|
|
75
|
+
|
|
76
|
+
Already have a two-channel WAV (caller on channel 0, agent on channel 1)?
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
uvx hotato run --stereo your_call.wav --expect yield
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Or run the bundled self-test, offline, with zero setup:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
uvx hotato run --suite barge-in
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
$ uvx hotato run --suite barge-in
|
|
90
|
+
hotato [suite] stack=generic offline=True
|
|
91
|
+
8/8 events pass (failed=0)
|
|
92
|
+
[PASS] 01-hard-interruption: did_yield=True seconds_to_yield=0.50s talk_over=0.50s
|
|
93
|
+
[PASS] 02-backchannel-mhm: did_yield=False seconds_to_yield=- talk_over=1.57s
|
|
94
|
+
[PASS] 03-filler-start: did_yield=True seconds_to_yield=0.65s talk_over=0.56s
|
|
95
|
+
[PASS] 04-correction: did_yield=True seconds_to_yield=0.50s talk_over=0.50s
|
|
96
|
+
[PASS] 05-telephony-8khz: did_yield=True seconds_to_yield=0.50s talk_over=0.50s
|
|
97
|
+
[PASS] 06-double-talk: did_yield=True seconds_to_yield=1.05s talk_over=1.05s
|
|
98
|
+
[PASS] 07-echo-bleed: did_yield=False seconds_to_yield=- talk_over=3.00s
|
|
99
|
+
[PASS] 08-rapid-turn-taking: did_yield=True seconds_to_yield=0.50s talk_over=0.50s
|
|
100
|
+
exit_code=0
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This self-test proves the tool itself behaves. Point it at a real call to measure
|
|
104
|
+
your agent.
|
|
105
|
+
|
|
106
|
+
Even faster: one command that scores, renders the visual report, and opens it.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
uvx hotato doctor --stereo your_call.wav # or plain `uvx hotato doctor` for the self-test
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## What you get
|
|
113
|
+
|
|
114
|
+
One scorer, and every surface you need around it. Each line below is one command.
|
|
115
|
+
|
|
116
|
+
- **`doctor`**, the 5-minute path: score a recording (or the bundled self-test),
|
|
117
|
+
write the visual HTML report, open it. `uvx hotato doctor --stereo call.wav`
|
|
118
|
+
- **`report`**, a self-contained visual report: per-event SVG timelines, analytics,
|
|
119
|
+
a per-frame inspector, print CSS for PDF, and regression deltas with
|
|
120
|
+
`--base base.json`. `uvx hotato report --stereo call.wav --out report.html`
|
|
121
|
+
- **`team`**, the trend view: aggregate a directory of runs into pass rate over
|
|
122
|
+
time plus mean/median/p90 talk-over and time-to-yield.
|
|
123
|
+
`uvx hotato team runs/ --html team.html`
|
|
124
|
+
- **`export`**, research-grade CSVs: `events.csv`, `frames.csv`, `envelope.json`,
|
|
125
|
+
columns documented in-file. `uvx hotato export --stereo call.wav --out research/`
|
|
126
|
+
- **Pytest plugin**, auto-registered on install: a `hotato_score` fixture and a
|
|
127
|
+
session gate that fails the run on a regression. `pytest --hotato-suite`
|
|
128
|
+
- **MCP tool**: one tool, `voice_eval_run`; pass `report_path` and the envelope
|
|
129
|
+
comes back with the written HTML report. `uvx --from "hotato[mcp]" hotato-mcp`
|
|
130
|
+
- **PR check**: a sticky PR comment with the results table and deltas, and a gate
|
|
131
|
+
on regression. Copy `.github/workflows/hotato.yml` into your repo.
|
|
132
|
+
- **Tiered corpus suites**: 112 deterministic scenarios across silver and gold
|
|
133
|
+
tiers, plus defect suites that must fail.
|
|
134
|
+
`hotato run --suite barge-in --scenarios corpus/suites/gold/scenarios --audio corpus/suites/gold/audio`
|
|
135
|
+
|
|
136
|
+
- **`benchmark`**, comparable stack runs: score your captured battery per stack, then compare result files side by side. `hotato benchmark --stack livekit --recordings captures/` then `hotato benchmark compare a.json b.json`
|
|
137
|
+
Deep detail: [`docs/REPORTS.md`](docs/REPORTS.md), [`docs/PYTEST.md`](docs/PYTEST.md),
|
|
138
|
+
[`docs/SUITES.md`](docs/SUITES.md), [`docs/CI.md`](docs/CI.md).
|
|
139
|
+
|
|
140
|
+
## What it measures
|
|
141
|
+
|
|
142
|
+
It scores the audio timing of turn-taking. Per event, three objective signals:
|
|
143
|
+
|
|
144
|
+
- `did_yield`: did the agent stop talking for the caller?
|
|
145
|
+
- `seconds_to_yield`: how long that took.
|
|
146
|
+
- `talk_over_sec`: how many seconds it kept talking over the caller first.
|
|
147
|
+
|
|
148
|
+
From those it renders a `PASS` or `FAIL` against expected behavior: a good agent
|
|
149
|
+
yields to a real interruption and holds through a backchannel like "mhm".
|
|
150
|
+
|
|
151
|
+
The bundled 8-scenario battery covers hard interruption, backchannel,
|
|
152
|
+
filler-start, correction, 8 kHz telephony, double-talk, echo-bleed, and rapid
|
|
153
|
+
turn-taking.
|
|
154
|
+
|
|
155
|
+
## Scope
|
|
156
|
+
|
|
157
|
+
Each limit is a property of how the scoring works.
|
|
158
|
+
|
|
159
|
+
- **Frame-by-frame timing you can verify.** Every number is a measurement against
|
|
160
|
+
a published, overridable threshold, inspectable with `--dump-frames`.
|
|
161
|
+
- **Speech energy over time is the whole signal**, so scoring is deterministic and
|
|
162
|
+
runs offline on any recording.
|
|
163
|
+
- **Two channels are ground truth for overlap.** Mono runs with an onset label and
|
|
164
|
+
reports its overlap as an estimate.
|
|
165
|
+
- **Synthetic fixtures are the floor**: deterministic, with exact known timings, a
|
|
166
|
+
runnable floor and a regression guard. Real validity comes from your own
|
|
167
|
+
labelled calls (see `CONTRIBUTING.md`).
|
|
168
|
+
|
|
169
|
+
Full method, and the optional neural cross-check (`--backend neural`, Silero VAD):
|
|
170
|
+
`METHODOLOGY.md`.
|
|
171
|
+
|
|
172
|
+
## Install
|
|
173
|
+
|
|
174
|
+
`uvx` runs every command with zero install. To add it to a project:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
pip install hotato # core, stdlib-only, zero dependencies
|
|
178
|
+
pip install 'hotato[neural]' # optional Silero VAD cross-check
|
|
179
|
+
pip install 'hotato[livekit]' # LiveKit live capture
|
|
180
|
+
pip install 'hotato[pipecat]' # Pipecat live capture
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Usage
|
|
184
|
+
|
|
185
|
+
Capture a real call from your stack. Vapi and Twilio need only an API key:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Vapi: an API key and a call id
|
|
189
|
+
export VAPI_API_KEY=...
|
|
190
|
+
uvx hotato capture --stack vapi --call-id <call-id>
|
|
191
|
+
|
|
192
|
+
# Twilio dual-channel recording
|
|
193
|
+
export TWILIO_ACCOUNT_SID=AC... TWILIO_AUTH_TOKEN=...
|
|
194
|
+
uvx hotato capture --stack twilio --recording-sid RE...
|
|
195
|
+
|
|
196
|
+
# LiveKit or Pipecat: scaffold the recording config first
|
|
197
|
+
uvx hotato setup --stack livekit # then: hotato capture --stack livekit --caller a.wav --agent b.wav
|
|
198
|
+
uvx hotato setup --stack pipecat # then: hotato capture --stack pipecat --stereo captured.wav
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Every stack, and Retell's status, is in [`adapters/README.md`](adapters/README.md).
|
|
202
|
+
|
|
203
|
+
Every failing event carries exactly one fix:
|
|
204
|
+
|
|
205
|
+
- **`config`**: a concrete knob for your stack (`livekit`, `pipecat`, `vapi`, or
|
|
206
|
+
`generic`), the direction to move it, and the trade-off it makes.
|
|
207
|
+
- **`engagement-control`**: the one failure a sensitivity dial cannot solve.
|
|
208
|
+
Telling a genuine bid for the floor apart from a backchannel is an open research
|
|
209
|
+
problem, so the pointer names the kind of fix, high-level and vendor-neutral: a
|
|
210
|
+
learned engagement-control / addressee-detection layer. It fires only when a
|
|
211
|
+
battery fails on both axes at once.
|
|
212
|
+
|
|
213
|
+
## The MCP tool
|
|
214
|
+
|
|
215
|
+
Run it as a one-tool MCP server (stdio), so an agent can run the eval mid-task:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
uvx --from "hotato[mcp]" hotato-mcp
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
It exposes exactly one tool, `voice_eval_run`, returning the same JSON envelope as
|
|
222
|
+
the CLI, with the scope and limits stated inline in the tool description. Pass an
|
|
223
|
+
optional `report_path` and it also writes the visual HTML report; the returned
|
|
224
|
+
envelope carries the absolute path.
|
|
225
|
+
|
|
226
|
+
## CI
|
|
227
|
+
|
|
228
|
+
`run` exits non-zero on a regression, straight into a PR gate:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
uvx hotato run --suite barge-in --format json
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Exit codes: `0` all pass (or `--no-fail`), `1` a regression, `2` usage or IO error.
|
|
235
|
+
|
|
236
|
+
Two ready-made gates sit on top. Copy `.github/workflows/hotato.yml` for a PR
|
|
237
|
+
check with a sticky results comment (`docs/CI.md`), or add `--hotato-suite` to
|
|
238
|
+
your existing pytest run (`docs/PYTEST.md`).
|
|
239
|
+
|
|
240
|
+
## Contributing
|
|
241
|
+
|
|
242
|
+
Bug fixes, scorer tuning, docs, and new scenarios are all welcome. The highest
|
|
243
|
+
value contribution is a real, labelled call fixture: synthetic fixtures make the
|
|
244
|
+
eval runnable, real recordings make it credible. The full path is
|
|
245
|
+
[`docs/SUBMITTING.md`](docs/SUBMITTING.md), and the
|
|
246
|
+
[corpus-submission issue form](https://github.com/attenlabs/hotato/issues/new?template=corpus_submission.yml)
|
|
247
|
+
walks you through it. Governance: `CONTRIBUTING.md` and `docs/CORPUS-GOVERNANCE.md`.
|
|
248
|
+
|
|
249
|
+
## Why "hotato"
|
|
250
|
+
|
|
251
|
+
Good turn-taking is a game of hot potato: take your turn, then pass it, fast and
|
|
252
|
+
clean. Fumble it and you miss a real interruption; clutch it and you talk over the
|
|
253
|
+
caller. Hotato catches both on your own recordings and points each at a fix.
|
|
254
|
+
|
|
255
|
+
## License
|
|
256
|
+
|
|
257
|
+
MIT (`LICENSE`). The open core stays open and is never relicensed.
|
hotato-0.1.0/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://hotato.dev">
|
|
3
|
+
<img src=".github/banner.png" alt="hotato: the open, offline turn-taking eval for voice agents" width="840">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h1 align="center">
|
|
8
|
+
<img src="docs/assets/mascot.svg" alt="" width="26" align="top"> hotato
|
|
9
|
+
</h1>
|
|
10
|
+
|
|
11
|
+
<p align="center"><b>An open, offline tool that scores voice-agent turn-taking from a call recording.</b></p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
|
|
15
|
+
<img alt="Python 3.9 to 3.13" src="https://img.shields.io/badge/python-3.9%20to%203.13-blue.svg">
|
|
16
|
+
<img alt="tests: passing" src="https://img.shields.io/badge/tests-passing-brightgreen.svg">
|
|
17
|
+
<img alt="build: passing" src="https://img.shields.io/badge/build-passing-brightgreen.svg">
|
|
18
|
+
<a href="https://hotato.dev"><img alt="site: hotato.dev" src="https://img.shields.io/badge/site-hotato.dev-e2470f.svg"></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
Built for anyone shipping voice agents on LiveKit, Pipecat, Vapi, Retell, or Twilio.<br>
|
|
23
|
+
Runs on your machine, so your call audio stays with you.
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
Point it at one of your own call recordings. It shows where your agent talked over
|
|
27
|
+
the caller, or missed a real interruption, and points each failure at the config
|
|
28
|
+
knob that fixes it. Every result is reproducible timing you can verify frame by
|
|
29
|
+
frame and gate a PR on.
|
|
30
|
+
|
|
31
|
+
## Quickstart (60 seconds)
|
|
32
|
+
|
|
33
|
+
Already have a two-channel WAV (caller on channel 0, agent on channel 1)?
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uvx hotato run --stereo your_call.wav --expect yield
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Or run the bundled self-test, offline, with zero setup:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
uvx hotato run --suite barge-in
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
$ uvx hotato run --suite barge-in
|
|
47
|
+
hotato [suite] stack=generic offline=True
|
|
48
|
+
8/8 events pass (failed=0)
|
|
49
|
+
[PASS] 01-hard-interruption: did_yield=True seconds_to_yield=0.50s talk_over=0.50s
|
|
50
|
+
[PASS] 02-backchannel-mhm: did_yield=False seconds_to_yield=- talk_over=1.57s
|
|
51
|
+
[PASS] 03-filler-start: did_yield=True seconds_to_yield=0.65s talk_over=0.56s
|
|
52
|
+
[PASS] 04-correction: did_yield=True seconds_to_yield=0.50s talk_over=0.50s
|
|
53
|
+
[PASS] 05-telephony-8khz: did_yield=True seconds_to_yield=0.50s talk_over=0.50s
|
|
54
|
+
[PASS] 06-double-talk: did_yield=True seconds_to_yield=1.05s talk_over=1.05s
|
|
55
|
+
[PASS] 07-echo-bleed: did_yield=False seconds_to_yield=- talk_over=3.00s
|
|
56
|
+
[PASS] 08-rapid-turn-taking: did_yield=True seconds_to_yield=0.50s talk_over=0.50s
|
|
57
|
+
exit_code=0
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
This self-test proves the tool itself behaves. Point it at a real call to measure
|
|
61
|
+
your agent.
|
|
62
|
+
|
|
63
|
+
Even faster: one command that scores, renders the visual report, and opens it.
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uvx hotato doctor --stereo your_call.wav # or plain `uvx hotato doctor` for the self-test
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## What you get
|
|
70
|
+
|
|
71
|
+
One scorer, and every surface you need around it. Each line below is one command.
|
|
72
|
+
|
|
73
|
+
- **`doctor`**, the 5-minute path: score a recording (or the bundled self-test),
|
|
74
|
+
write the visual HTML report, open it. `uvx hotato doctor --stereo call.wav`
|
|
75
|
+
- **`report`**, a self-contained visual report: per-event SVG timelines, analytics,
|
|
76
|
+
a per-frame inspector, print CSS for PDF, and regression deltas with
|
|
77
|
+
`--base base.json`. `uvx hotato report --stereo call.wav --out report.html`
|
|
78
|
+
- **`team`**, the trend view: aggregate a directory of runs into pass rate over
|
|
79
|
+
time plus mean/median/p90 talk-over and time-to-yield.
|
|
80
|
+
`uvx hotato team runs/ --html team.html`
|
|
81
|
+
- **`export`**, research-grade CSVs: `events.csv`, `frames.csv`, `envelope.json`,
|
|
82
|
+
columns documented in-file. `uvx hotato export --stereo call.wav --out research/`
|
|
83
|
+
- **Pytest plugin**, auto-registered on install: a `hotato_score` fixture and a
|
|
84
|
+
session gate that fails the run on a regression. `pytest --hotato-suite`
|
|
85
|
+
- **MCP tool**: one tool, `voice_eval_run`; pass `report_path` and the envelope
|
|
86
|
+
comes back with the written HTML report. `uvx --from "hotato[mcp]" hotato-mcp`
|
|
87
|
+
- **PR check**: a sticky PR comment with the results table and deltas, and a gate
|
|
88
|
+
on regression. Copy `.github/workflows/hotato.yml` into your repo.
|
|
89
|
+
- **Tiered corpus suites**: 112 deterministic scenarios across silver and gold
|
|
90
|
+
tiers, plus defect suites that must fail.
|
|
91
|
+
`hotato run --suite barge-in --scenarios corpus/suites/gold/scenarios --audio corpus/suites/gold/audio`
|
|
92
|
+
|
|
93
|
+
- **`benchmark`**, comparable stack runs: score your captured battery per stack, then compare result files side by side. `hotato benchmark --stack livekit --recordings captures/` then `hotato benchmark compare a.json b.json`
|
|
94
|
+
Deep detail: [`docs/REPORTS.md`](docs/REPORTS.md), [`docs/PYTEST.md`](docs/PYTEST.md),
|
|
95
|
+
[`docs/SUITES.md`](docs/SUITES.md), [`docs/CI.md`](docs/CI.md).
|
|
96
|
+
|
|
97
|
+
## What it measures
|
|
98
|
+
|
|
99
|
+
It scores the audio timing of turn-taking. Per event, three objective signals:
|
|
100
|
+
|
|
101
|
+
- `did_yield`: did the agent stop talking for the caller?
|
|
102
|
+
- `seconds_to_yield`: how long that took.
|
|
103
|
+
- `talk_over_sec`: how many seconds it kept talking over the caller first.
|
|
104
|
+
|
|
105
|
+
From those it renders a `PASS` or `FAIL` against expected behavior: a good agent
|
|
106
|
+
yields to a real interruption and holds through a backchannel like "mhm".
|
|
107
|
+
|
|
108
|
+
The bundled 8-scenario battery covers hard interruption, backchannel,
|
|
109
|
+
filler-start, correction, 8 kHz telephony, double-talk, echo-bleed, and rapid
|
|
110
|
+
turn-taking.
|
|
111
|
+
|
|
112
|
+
## Scope
|
|
113
|
+
|
|
114
|
+
Each limit is a property of how the scoring works.
|
|
115
|
+
|
|
116
|
+
- **Frame-by-frame timing you can verify.** Every number is a measurement against
|
|
117
|
+
a published, overridable threshold, inspectable with `--dump-frames`.
|
|
118
|
+
- **Speech energy over time is the whole signal**, so scoring is deterministic and
|
|
119
|
+
runs offline on any recording.
|
|
120
|
+
- **Two channels are ground truth for overlap.** Mono runs with an onset label and
|
|
121
|
+
reports its overlap as an estimate.
|
|
122
|
+
- **Synthetic fixtures are the floor**: deterministic, with exact known timings, a
|
|
123
|
+
runnable floor and a regression guard. Real validity comes from your own
|
|
124
|
+
labelled calls (see `CONTRIBUTING.md`).
|
|
125
|
+
|
|
126
|
+
Full method, and the optional neural cross-check (`--backend neural`, Silero VAD):
|
|
127
|
+
`METHODOLOGY.md`.
|
|
128
|
+
|
|
129
|
+
## Install
|
|
130
|
+
|
|
131
|
+
`uvx` runs every command with zero install. To add it to a project:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pip install hotato # core, stdlib-only, zero dependencies
|
|
135
|
+
pip install 'hotato[neural]' # optional Silero VAD cross-check
|
|
136
|
+
pip install 'hotato[livekit]' # LiveKit live capture
|
|
137
|
+
pip install 'hotato[pipecat]' # Pipecat live capture
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Usage
|
|
141
|
+
|
|
142
|
+
Capture a real call from your stack. Vapi and Twilio need only an API key:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Vapi: an API key and a call id
|
|
146
|
+
export VAPI_API_KEY=...
|
|
147
|
+
uvx hotato capture --stack vapi --call-id <call-id>
|
|
148
|
+
|
|
149
|
+
# Twilio dual-channel recording
|
|
150
|
+
export TWILIO_ACCOUNT_SID=AC... TWILIO_AUTH_TOKEN=...
|
|
151
|
+
uvx hotato capture --stack twilio --recording-sid RE...
|
|
152
|
+
|
|
153
|
+
# LiveKit or Pipecat: scaffold the recording config first
|
|
154
|
+
uvx hotato setup --stack livekit # then: hotato capture --stack livekit --caller a.wav --agent b.wav
|
|
155
|
+
uvx hotato setup --stack pipecat # then: hotato capture --stack pipecat --stereo captured.wav
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Every stack, and Retell's status, is in [`adapters/README.md`](adapters/README.md).
|
|
159
|
+
|
|
160
|
+
Every failing event carries exactly one fix:
|
|
161
|
+
|
|
162
|
+
- **`config`**: a concrete knob for your stack (`livekit`, `pipecat`, `vapi`, or
|
|
163
|
+
`generic`), the direction to move it, and the trade-off it makes.
|
|
164
|
+
- **`engagement-control`**: the one failure a sensitivity dial cannot solve.
|
|
165
|
+
Telling a genuine bid for the floor apart from a backchannel is an open research
|
|
166
|
+
problem, so the pointer names the kind of fix, high-level and vendor-neutral: a
|
|
167
|
+
learned engagement-control / addressee-detection layer. It fires only when a
|
|
168
|
+
battery fails on both axes at once.
|
|
169
|
+
|
|
170
|
+
## The MCP tool
|
|
171
|
+
|
|
172
|
+
Run it as a one-tool MCP server (stdio), so an agent can run the eval mid-task:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
uvx --from "hotato[mcp]" hotato-mcp
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
It exposes exactly one tool, `voice_eval_run`, returning the same JSON envelope as
|
|
179
|
+
the CLI, with the scope and limits stated inline in the tool description. Pass an
|
|
180
|
+
optional `report_path` and it also writes the visual HTML report; the returned
|
|
181
|
+
envelope carries the absolute path.
|
|
182
|
+
|
|
183
|
+
## CI
|
|
184
|
+
|
|
185
|
+
`run` exits non-zero on a regression, straight into a PR gate:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
uvx hotato run --suite barge-in --format json
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Exit codes: `0` all pass (or `--no-fail`), `1` a regression, `2` usage or IO error.
|
|
192
|
+
|
|
193
|
+
Two ready-made gates sit on top. Copy `.github/workflows/hotato.yml` for a PR
|
|
194
|
+
check with a sticky results comment (`docs/CI.md`), or add `--hotato-suite` to
|
|
195
|
+
your existing pytest run (`docs/PYTEST.md`).
|
|
196
|
+
|
|
197
|
+
## Contributing
|
|
198
|
+
|
|
199
|
+
Bug fixes, scorer tuning, docs, and new scenarios are all welcome. The highest
|
|
200
|
+
value contribution is a real, labelled call fixture: synthetic fixtures make the
|
|
201
|
+
eval runnable, real recordings make it credible. The full path is
|
|
202
|
+
[`docs/SUBMITTING.md`](docs/SUBMITTING.md), and the
|
|
203
|
+
[corpus-submission issue form](https://github.com/attenlabs/hotato/issues/new?template=corpus_submission.yml)
|
|
204
|
+
walks you through it. Governance: `CONTRIBUTING.md` and `docs/CORPUS-GOVERNANCE.md`.
|
|
205
|
+
|
|
206
|
+
## Why "hotato"
|
|
207
|
+
|
|
208
|
+
Good turn-taking is a game of hot potato: take your turn, then pass it, fast and
|
|
209
|
+
clean. Fumble it and you miss a real interruption; clutch it and you talk over the
|
|
210
|
+
caller. Hotato catches both on your own recordings and points each at a fix.
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT (`LICENSE`). The open core stays open and is never relicensed.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "hotato"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Hotato: the open turn-taking eval for voice agents. Does your agent drop the turn, or hog it? Score barge-in / talk-over / backchannel / endpointing from a call recording, offline, with an honest fix map. MIT."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Attention Labs, Inc." }]
|
|
13
|
+
keywords = [
|
|
14
|
+
"hotato", "voice-ai", "voice-agents", "evals", "barge-in", "turn-taking",
|
|
15
|
+
"mcp", "agent-native", "observability", "reliability", "livekit",
|
|
16
|
+
"pipecat", "vapi",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Topic :: Multimedia :: Sound/Audio :: Analysis",
|
|
22
|
+
"Topic :: Software Development :: Testing",
|
|
23
|
+
]
|
|
24
|
+
# The core has ZERO required third-party dependencies: it is stdlib-only so it
|
|
25
|
+
# runs anywhere with `uvx` and adds no supply-chain surface. numpy is used only
|
|
26
|
+
# as an optional accelerator if it already happens to be importable.
|
|
27
|
+
dependencies = []
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
# The one-tool MCP server needs the MCP SDK. Kept optional so the CLI stays
|
|
31
|
+
# dependency-free and zero-install.
|
|
32
|
+
mcp = ["mcp>=1.2.0"]
|
|
33
|
+
dev = ["pytest>=7", "jsonschema>=4"]
|
|
34
|
+
|
|
35
|
+
# Per-stack capture extras. Vapi and Twilio capture use only stdlib (urllib +
|
|
36
|
+
# your API key), so `uvx hotato capture --stack vapi --call-id <id>` needs
|
|
37
|
+
# NOTHING extra -- these two extras are intentionally empty and exist so the
|
|
38
|
+
# documented `uvx 'hotato[vapi]'` / `hotato[twilio]` install still resolves.
|
|
39
|
+
# LiveKit and Pipecat LIVE capture run inside your own pipeline and genuinely
|
|
40
|
+
# need their frameworks; those are imported lazily and only on the live path.
|
|
41
|
+
vapi = []
|
|
42
|
+
twilio = []
|
|
43
|
+
livekit = ["livekit", "livekit-agents"]
|
|
44
|
+
pipecat = ["pipecat-ai"]
|
|
45
|
+
# OPTIONAL, NON-REFERENCE neural VAD cross-check (Silero VAD, MIT). Strictly
|
|
46
|
+
# opt-in via `--backend neural`; the zero-dependency energy core stays the
|
|
47
|
+
# reference for every published/golden number and is never affected by this
|
|
48
|
+
# extra. onnxruntime keeps inference CPU-only and lightweight (no torch needed at
|
|
49
|
+
# runtime). Absent this extra, `--backend neural` errors cleanly, never falling
|
|
50
|
+
# back to energy.
|
|
51
|
+
neural = ["silero-vad>=5", "onnxruntime>=1.16", "numpy>=1.21"]
|
|
52
|
+
# Everything a contributor might want to exercise the live capture paths locally.
|
|
53
|
+
all = ["mcp>=1.2.0", "livekit", "livekit-agents", "pipecat-ai", "silero-vad>=5", "onnxruntime>=1.16", "numpy>=1.21"]
|
|
54
|
+
|
|
55
|
+
[project.scripts]
|
|
56
|
+
hotato = "hotato.cli:main"
|
|
57
|
+
hotato-mcp = "hotato.mcp_server:main"
|
|
58
|
+
|
|
59
|
+
# Pytest integration (the `hotato_score` fixture and the opt-in --hotato-suite
|
|
60
|
+
# session gate). Auto-discovered by pytest when hotato is installed; inert
|
|
61
|
+
# unless the fixture or flag is actually used, and needs nothing beyond pytest
|
|
62
|
+
# itself (the scoring core stays stdlib-only).
|
|
63
|
+
[project.entry-points.pytest11]
|
|
64
|
+
hotato = "hotato.pytest_plugin"
|
|
65
|
+
|
|
66
|
+
[project.urls]
|
|
67
|
+
Repository = "https://github.com/attenlabs/hotato"
|
|
68
|
+
Homepage = "https://hotato.dev"
|
|
69
|
+
"Open engine (upstream)" = "https://github.com/quantumCF/voice-agent-barge-in-tests"
|
|
70
|
+
|
|
71
|
+
[tool.setuptools.packages.find]
|
|
72
|
+
where = ["src"]
|
|
73
|
+
|
|
74
|
+
[tool.setuptools.package-data]
|
|
75
|
+
hotato = ["data/scenarios/*.json", "data/audio/*.wav", "schema/*.json"]
|
hotato-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""hotato: the open turn-taking eval for voice agents.
|
|
2
|
+
|
|
3
|
+
Does your agent drop the turn, or hog it? Free (MIT), self-hostable,
|
|
4
|
+
zero-install, and offline. Its primary consumer is an AI agent: grab it as a CLI
|
|
5
|
+
(``uvx hotato ...``) or as a one-tool MCP server mid-task. It scores voice-agent
|
|
6
|
+
turn-taking - barge-in, overlap/talk-over, and backchannel handling - from a
|
|
7
|
+
call recording, returns a machine-readable verdict, and is the only such tool
|
|
8
|
+
that points a surfaced failure at the KIND of fix it needs: a learned
|
|
9
|
+
engagement-control / addressee-detection layer (an open research problem, not a
|
|
10
|
+
config knob) when the failure is a discrimination one no threshold can solve.
|
|
11
|
+
The pointer is vendor-neutral and names no product.
|
|
12
|
+
|
|
13
|
+
Honesty is the point, not a footnote: there is no fabricated accuracy anywhere.
|
|
14
|
+
The numbers are reproducible timing measurements with an exposed method and an
|
|
15
|
+
explicit ceiling.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from .core import LIMITS, SUITE_ID, run_single, run_suite
|
|
19
|
+
|
|
20
|
+
from ._engine.vad import register_neural_backend as _register_neural_backend
|
|
21
|
+
from .neural import build_silero_backend as _build_silero_backend
|
|
22
|
+
|
|
23
|
+
# Register the OPTIONAL, non-reference neural VAD backend (Silero VAD, MIT). This
|
|
24
|
+
# only stores the factory reference: the model and its extra are imported lazily,
|
|
25
|
+
# and only if backend="neural" is actually requested -- so importing hotato stays
|
|
26
|
+
# zero-dependency and the energy reference path is untouched. With the [neural]
|
|
27
|
+
# extra absent, a neural request raises a clean BackendUnavailable (never a silent
|
|
28
|
+
# fallback to energy that could change a published number).
|
|
29
|
+
_register_neural_backend(_build_silero_backend)
|
|
30
|
+
|
|
31
|
+
__version__ = "0.1.0"
|
|
32
|
+
|
|
33
|
+
__all__ = ["run_single", "run_suite", "LIMITS", "SUITE_ID", "__version__"]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""voice-agent-barge-in-tests: a dependency-light harness for measuring the three
|
|
2
|
+
objective barge-in signals (did the agent yield, time to yield, talk-over
|
|
3
|
+
seconds) from a voice-agent call recording.
|
|
4
|
+
|
|
5
|
+
See the repository README for the failure mode this tests and how to wire it
|
|
6
|
+
into CI. This package measures timing from audio and makes no accuracy claim
|
|
7
|
+
about any detector.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from .audio import Signal, read_wav, write_wav
|
|
11
|
+
from .score import (
|
|
12
|
+
ScoreConfig,
|
|
13
|
+
ScoreResult,
|
|
14
|
+
Verdict,
|
|
15
|
+
evaluate,
|
|
16
|
+
score_channels,
|
|
17
|
+
score_stereo,
|
|
18
|
+
)
|
|
19
|
+
from .vad import (
|
|
20
|
+
BackendUnavailable,
|
|
21
|
+
VADParams,
|
|
22
|
+
clear_neural_backend,
|
|
23
|
+
energy_vad,
|
|
24
|
+
neural_vad,
|
|
25
|
+
register_neural_backend,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
__version__ = "0.1.0"
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"Signal",
|
|
32
|
+
"read_wav",
|
|
33
|
+
"write_wav",
|
|
34
|
+
"ScoreConfig",
|
|
35
|
+
"ScoreResult",
|
|
36
|
+
"Verdict",
|
|
37
|
+
"evaluate",
|
|
38
|
+
"score_channels",
|
|
39
|
+
"score_stereo",
|
|
40
|
+
"VADParams",
|
|
41
|
+
"energy_vad",
|
|
42
|
+
"neural_vad",
|
|
43
|
+
"register_neural_backend",
|
|
44
|
+
"clear_neural_backend",
|
|
45
|
+
"BackendUnavailable",
|
|
46
|
+
"__version__",
|
|
47
|
+
]
|