Model card: the Realtime Context Standard, and Pipecat's processors
Browse files
README.md
CHANGED
|
@@ -16,86 +16,85 @@ tags:
|
|
| 16 |
- expressive-tts
|
| 17 |
---
|
| 18 |
|
| 19 |
-
# Pipecat
|
| 20 |
|
| 21 |
-
Two small CPU models for
|
| 22 |
|
| 23 |
-
- **Tone reader** (`reader/`)
|
| 24 |
-
- **Tone tagger** (`tagger/`)
|
| 25 |
|
| 26 |
-
Each
|
| 27 |
|
| 28 |
-
##
|
| 29 |
|
| 30 |
-
|
| 31 |
|
| 32 |
-
```
|
| 33 |
-
|
|
|
|
| 34 |
```
|
| 35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
```python
|
| 37 |
-
from
|
| 38 |
-
from
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
|
|
|
|
|
|
| 42 |
```
|
| 43 |
|
|
|
|
|
|
|
| 44 |
## Releases
|
| 45 |
|
| 46 |
| Tag | Folder | Model |
|
| 47 |
| --- | --- | --- |
|
| 48 |
-
| `reader-rc1` | `reader/` |
|
| 49 |
-
| `tagger-rc1` | `tagger/17m`, `tagger/32m` | Ettin 17M
|
| 50 |
|
| 51 |
-
|
| 52 |
|
| 53 |
-
##
|
| 54 |
|
| 55 |
-
|
| 56 |
|
| 57 |
| | Real calls (1,500 turns) | Calls with more feeling (897 turns) |
|
| 58 |
| --- | --- | --- |
|
| 59 |
| Emotion macro-F1 | 0.940 (neutral, happy) | 0.598 (all nine) |
|
| 60 |
-
|
|
| 61 |
-
|
|
| 62 |
-
| Calibration error: emotion, move, sarcasm | 0.079, 0.027, 0.016 | 0.036, 0.039, 0.014 |
|
| 63 |
-
|
| 64 |
-
p95 per turn on 4 CPU threads (Apple M1 Max): 5.0 ms with the turn before, 3.7 ms without; 11.9 ms on 1 thread. The 16-bit file reads the same tags at half the size.
|
| 65 |
|
| 66 |
-
|
| 67 |
|
| 68 |
-
|
| 69 |
|
| 70 |
-
| |
|
| 71 |
-
| --- | --- | --- |
|
| 72 |
-
|
|
| 73 |
-
|
|
| 74 |
-
|
| 75 |
-
On tone-bench, phonellm-mini with the 17M after it scores 90.9 over two passes, judged by Claude Opus 5.5: expression 97.1 (recall 100.0, precision 94.4). With the tagger's rules instead it scores 90.0, and phonellm-mini alone 57.9.
|
| 76 |
|
| 77 |
-
|
| 78 |
|
| 79 |
## Data
|
| 80 |
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
The tagger's corpus: 999, 2,000, 1,000 and 1,000 synthetic support calls. Claude wrote each scenario; deployment LLMs held the calls through a real Pipecat pipeline; a Claude teacher labeled every sentence without changing a word; another vendor's model reviewed each reply. Half of v2's calls ask to breathe, and each of v3's has a moment for a rare delivery. Each call's JSON has its spec, scenario, replies, the teacher's labels and the reviewer's verdicts, and its breath pass: which replies breathe, drawn at people's rate for their length, and the sentence the teacher chose for each breath. The rows training reads (`train`, `dev` and `test.jsonl`) are split by domain, with `stats.json`. The domain families tone-bench tests are left out. Names, emails, phone and account numbers in the calls are made up.
|
| 84 |
-
|
| 85 |
-
### Reader: `data/reader`
|
| 86 |
-
|
| 87 |
-
What the reader's training and checks read, with no third-party text in it: the files that are ours as they are (rc1's run, its teachers' soft labels, label sets of our own lines), and stand-ins for the files that mix our lines with lines from public datasets, which say how to make each of those lines again from its source. `rebuild/manifest.json` pins every source and every file's SHA-256, and `lab.reader.pipeline.fetch` in pipecat-tone downloads the sources and rebuilds the exact files training reads. [data/reader/README.md](data/reader/README.md) has the details.
|
| 88 |
|
| 89 |
-
The public datasets, each under its own licence: NatCS (CDLA-Permissive-2.0); Taskmaster-1, -2 and -3 (CC BY 4.0); ABCD
|
| 90 |
|
| 91 |
-
##
|
| 92 |
|
| 93 |
-
- For shaping how a voice agent sounds
|
| 94 |
- English only. The tagger learned from support calls; the reader from support, assistant and meeting conversations.
|
| 95 |
-
- The reader reads words, not voices:
|
| 96 |
-
- The tagger
|
| 97 |
-
- Scores
|
| 98 |
|
| 99 |
## Licence
|
| 100 |
|
| 101 |
-
BSD-2-Clause: both models and the data here
|
|
|
|
| 16 |
- expressive-tts
|
| 17 |
---
|
| 18 |
|
| 19 |
+
# Pipecat Tone
|
| 20 |
|
| 21 |
+
Two small CPU models for [Pipecat](https://github.com/pipecat-ai/pipecat) voice agents, built for Pipecat's [Realtime Context Standard](https://docs.pipecat.ai)<!-- placeholder: the standard's docs page -->:
|
| 22 |
|
| 23 |
+
- **Tone reader** (`reader/`) reads how each user turn was meant, from its words: the emotion and whether it's sarcastic, with calibrated confidences.
|
| 24 |
+
- **Tone tagger** (`tagger/`) voices an LLM's plain reply, a sentence at a time: a delivery, slow spans for details, stressed words, sounds and breaths, in the names the TTS performs.
|
| 25 |
|
| 26 |
+
Each runs in milliseconds on a CPU.
|
| 27 |
|
| 28 |
+
## Realtime Context Standard
|
| 29 |
|
| 30 |
+
The standard carries how a conversation sounds alongside its words. A reading of how the user spoke heads their message in the LLM's context, and each reply reaches the TTS with the expression tags it performs. The reader writes the reading; the tagger writes the tags, so the LLM writes only words.
|
| 31 |
|
| 32 |
+
```text
|
| 33 |
+
LLM reads: ([emotion angry=0.71, neutral=0.20],[sarcasm value=0.99]) Oh great, a forty minute wait.
|
| 34 |
+
TTS gets: <<apologetic>> Sorry about the wait. [[quick breath]] Your order, <<slow: 48213>>, ships ^^today^^.
|
| 35 |
```
|
| 36 |
|
| 37 |
+
## Use
|
| 38 |
+
|
| 39 |
+
In Pipecat, install `pipecat-ai[tone]`, turn on `PipelineParams(enable_expressive_conversation=True)`, and add the two processors:
|
| 40 |
+
|
| 41 |
```python
|
| 42 |
+
from pipecat.processors.tone.reader import PipecatToneReader
|
| 43 |
+
from pipecat.processors.tone.tagger import PipecatToneTagger
|
| 44 |
|
| 45 |
+
pipeline = Pipeline([
|
| 46 |
+
transport.input(), stt, PipecatToneReader(), user_aggregator,
|
| 47 |
+
llm, PipecatToneTagger(), tts, transport.output(), assistant_aggregator,
|
| 48 |
+
])
|
| 49 |
```
|
| 50 |
|
| 51 |
+
The models download from here the first time a pipeline starts; `PipecatToneTagger(size="32m")` picks the larger tagger. Breaths need `ExpressionGuidance.BREATHE` in the expression policy.
|
| 52 |
+
|
| 53 |
## Releases
|
| 54 |
|
| 55 |
| Tag | Folder | Model |
|
| 56 |
| --- | --- | --- |
|
| 57 |
+
| `reader-rc1` | `reader/` | MiniLM-L6, 24.2M parameters: 48 MB (fp16) or 96 MB (fp32) |
|
| 58 |
+
| `tagger-rc1` | `tagger/17m`, `tagger/32m` | Ettin 17M or 32M, six heads, int8: 63 MB or 115 MB |
|
| 59 |
|
| 60 |
+
`MANIFEST.json` lists each model file's size and SHA-256.
|
| 61 |
|
| 62 |
+
## Scores
|
| 63 |
|
| 64 |
+
**Reader**, against the majority vote of three LLMs, on turns it never trained on:
|
| 65 |
|
| 66 |
| | Real calls (1,500 turns) | Calls with more feeling (897 turns) |
|
| 67 |
| --- | --- | --- |
|
| 68 |
| Emotion macro-F1 | 0.940 (neutral, happy) | 0.598 (all nine) |
|
| 69 |
+
| Sarcasm | 1 of 1,496 sincere turns called sarcastic | F1 0.887 |
|
| 70 |
+
| Calibration error: emotion, sarcasm | 0.079, 0.016 | 0.036, 0.014 |
|
|
|
|
|
|
|
|
|
|
| 71 |
|
| 72 |
+
p95 per turn on 4 CPU threads (Apple M1 Max): 5.0 ms.
|
| 73 |
|
| 74 |
+
**Tagger**, against its teacher's labels on 439 held-out calls (combined score):
|
| 75 |
|
| 76 |
+
| | Score | p50 per sentence, 1 thread |
|
| 77 |
+
| --- | --- | --- |
|
| 78 |
+
| 17M (default) | 0.753 | 13.8 ms |
|
| 79 |
+
| 32M | 0.767 | 37.1 ms |
|
|
|
|
|
|
|
| 80 |
|
| 81 |
+
It breathes at most once a reply, about as often as people do in turns that long (ICSI Meeting Corpus), each breath drawn as light, deep or an exhale at people's shares (59%, 36%, 5%).
|
| 82 |
|
| 83 |
## Data
|
| 84 |
|
| 85 |
+
- **Tagger** (`data/tagger/v0`–`v3`): 4,999 synthetic support calls, held by deployment LLMs through a real Pipecat pipeline, every sentence labeled by a Claude teacher, and split by domain. Names, emails and numbers are made up.
|
| 86 |
+
- **Reader** (`data/reader`): our own files, and stand-ins for lines from public datasets, which `rebuild/manifest.json` pins to their sources. No third-party text is hosted here.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
+
The reader's public datasets, each under its own licence: NatCS (CDLA-Permissive-2.0); Taskmaster-1, -2 and -3 (CC BY 4.0); ABCD, MultiWOZ 2.2 and STAR (MIT); CCPE-M and Harper Valley Bank (CC BY 4.0); the AMI Meeting Corpus's annotations (CC BY 4.0); DiPCo (CDLA-Permissive-1.0); DynaSent round 2 (CC BY 4.0); iSarcasmEval (MIT); GoEmotions (Apache 2.0); Civil Comments (CC0 1.0); the Gutenberg Dialogue Dataset (MIT). Topical-Chat's test splits (CDLA-Sharing-1.0) are for evaluation only.
|
| 89 |
|
| 90 |
+
## Limits
|
| 91 |
|
| 92 |
+
- For shaping how a voice agent sounds, not for judging or profiling the people it talks to.
|
| 93 |
- English only. The tagger learned from support calls; the reader from support, assistant and meeting conversations.
|
| 94 |
+
- The reader reads words, not voices: a flat transcript reads neutral.
|
| 95 |
+
- The tagger knows Cartesia, ElevenLabs, Fish Audio and MiniMax by name; another TTS is matched on the names it declares.
|
| 96 |
+
- Scores measure agreement with model labels, not with listeners.
|
| 97 |
|
| 98 |
## Licence
|
| 99 |
|
| 100 |
+
BSD-2-Clause ([LICENSE](LICENSE)): both models and the data here. The public datasets keep their own licences.
|