Skip to content

Commit d6de413

Browse files
Nash0x7E2coderabbitai[bot]cursoragent
authored
Add support for Cartesia STT (#602)
* Update Cartesia speech models * Fix STT event registration * Register STT events from module * Harden Cartesia STT lifecycle tests * Apply suggestions from code review Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Fix Cartesia example links * Fix pytest conftest collision in cartesia plugin tests. Remove plugins/cartesia/tests/conftest.py which conflicted with other plugin conftest modules during full-suite collection, and inline the integration API key guard in the cartesia test modules instead. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent aeeacb1 commit d6de413

14 files changed

Lines changed: 684 additions & 49 deletions

File tree

agents-core/vision_agents/core/stt/stt.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from vision_agents.core.edge.types import Participant
1010
from vision_agents.core.events.manager import EventManager
1111
from vision_agents.core.observability import MetricsCollector
12+
from vision_agents.core.stt import events
1213
from vision_agents.core.stt.events import (
1314
STTConnectedEvent,
1415
STTDisconnectedEvent,
@@ -87,6 +88,7 @@ def __init__(
8788
self.provider_name = provider_name or self.__class__.__name__
8889

8990
self.events = EventManager()
91+
self.events.register_events_from_module(events, ignore_not_compatible=True)
9092
self.metrics = MetricsCollector()
9193

9294
self._output: Stream[Transcript | TurnEnded | TurnStarted] = Stream()

plugins/cartesia/README.md

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[Cartesia](https://cartesia.ai) is a service that provides Speech-to-Text (STT) and Text-to-Speech (TTS) capabilities. It's designed for real-time voice applications, making it ideal for voice AI agents, transcription pipelines, and conversational interfaces.
44

5-
The Cartesia plugin for the Stream Python AI SDK allows you to add TTS functionality to your project.
5+
The Cartesia plugin for the Stream Python AI SDK allows you to add STT and TTS functionality to your project.
66

77
## Installation
88

@@ -16,19 +16,20 @@ uv add vision-agents-plugins-cartesia
1616

1717
## Examples
1818

19-
Read on for some key details and check out our [Cartesia examples](https://github.com/GetStream/vision-agents/tree/main/examples/other_examples/plugins_examples/tts_cartesia) to see working code samples:
19+
Read on for some key details and check out our [Cartesia examples](https://github.com/GetStream/Vision-Agents/tree/main/plugins/cartesia/example) to see working code samples:
2020

21-
- in [tts.py](https://github.com/GetStream/vision-agents/tree/main/examples/other_examples/plugins_examples/tts_cartesia/tts.py) we see a simple bot greeting users upon joining a call
22-
- in [narrator-example.py](https://github.com/GetStream/vision-agents/tree/main/examples/other_examples/plugins_examples/tts_cartesia/narrator-example.py) we see a well-prompted combination of a STT -> LLM -> TTS flow that leverages the powers of Cartesia's Sonic 3 model to narrate a creative story from the user's input
21+
- in [main.py](https://github.com/GetStream/Vision-Agents/blob/main/plugins/cartesia/example/main.py) we see a voice bot that uses Cartesia STT and TTS in a Stream call
22+
- in [narrator-example.py](https://github.com/GetStream/Vision-Agents/blob/main/plugins/cartesia/example/narrator-example.py) we see a well-prompted combination of an STT -> LLM -> TTS flow that leverages Cartesia's Ink and Sonic models to narrate a creative story from the user's input
2323

2424
## Initialisation
2525

26-
The Cartesia plugin for Stream exists in the form of the `TTS` class:
26+
The Cartesia plugin for Stream exposes `STT` and `TTS` classes:
2727

2828
```python
2929

3030
from vision_agents.plugins import cartesia
3131

32+
stt = cartesia.STT()
3233
tts = cartesia.TTS()
3334
```
3435

@@ -39,17 +40,39 @@ tts = cartesia.TTS()
3940

4041
## Parameters
4142

42-
These are the parameters available in the CartesiaTTS plugin for you to customise:
43+
These are the parameters available in the Cartesia STT plugin for you to customise:
44+
45+
| Name | Type | Default | Description |
46+
|---------------------|-----------------|----------------------------------------|---------------------------------------------------------------------------------------------------------------|
47+
| `api_key` | `str` or `None` | `None` | Your Cartesia API key. If not provided, the plugin will look for the `CARTESIA_API_KEY` environment variable. |
48+
| `model` | `str` | `"ink-2"` | ID of the Cartesia STT model to use. |
49+
| `sample_rate` | `int` | `16000` | Sample rate (in Hz) sent to Cartesia. |
50+
| `encoding` | `str` | `"pcm_s16le"` | PCM encoding sent to Cartesia. |
51+
| `cartesia_version` | `str` | `"2026-03-01"` | Cartesia API version used for the turn-detection websocket. |
52+
53+
These are the parameters available in the Cartesia TTS plugin for you to customise:
4354

4455
| Name | Type | Default | Description |
4556
|---------------|-----------------|------------------------------------------|---------------------------------------------------------------------------------------------------------------|
4657
| `api_key` | `str` or `None` | `None` | Your Cartesia API key. If not provided, the plugin will look for the `CARTESIA_API_KEY` environment variable. |
47-
| `model_id` | `str` | `"sonic-3"` | ID of the Cartesia STT or TTS model to use. Defaults to the recently released Sonic-3 |
58+
| `model_id` | `str` | `"sonic-3.5"` | ID of the Cartesia TTS model to use. |
4859
| `voice_id` | `str` or `None` | `"f9836c6e-a0bd-460e-9d3c-f7299fa60f94"` | ID of the voice to use for TTS responses. |
4960
| `sample_rate` | `int` | `16000` | Sample rate (in Hz) used for audio processing. |
5061

5162
## Functionality
5263

64+
### Send audio to transcribe speech
65+
66+
`STT` streams PCM audio to Cartesia Ink and emits transcript and turn events that Vision Agents can use for interruption and eager turn handling.
67+
68+
```python theme={null}
69+
agent = Agent(
70+
...,
71+
stt=cartesia.STT(),
72+
tts=cartesia.TTS(),
73+
)
74+
```
75+
5376
### Send text to convert to speech
5477

5578
The `send_iter()` method sends the text passed in for the service to synthesize

plugins/cartesia/example/README.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
# Stream + Cartesia TTS Bot Example
1+
# Stream + Cartesia Voice Bot Example
22

3-
This example demonstrates how to build a text-to-speech bot that joins a Stream video call and greets participants
4-
using [Cartesia's](https://cartesia.ai/?utm_medium=partner&utm_source=getstream) Sonic voices.
3+
This example demonstrates how to build a voice bot that joins a Stream video call, transcribes participants with Cartesia STT, and speaks responses with Cartesia TTS.
54

65
## What it does
76

8-
- 🤖 Creates a TTS bot that joins a Stream video call
9-
- 🌐 Opens a browser interface for users to join the call
10-
- 🔊 Greets users when they join using Cartesia TTS
11-
- 🎙️ Sends audio directly to the call in real-time
7+
- Creates a voice bot that joins a Stream video call
8+
- Uses Cartesia Ink for realtime STT and turn detection
9+
- Uses Cartesia Sonic for TTS responses
10+
- Uses OpenAI for the LLM response
1211

1312
## Prerequisites
1413

1514
1. **Stream Account**: Get your API credentials from [Stream Dashboard](https://getstream.io/try-for-free/?utm_source=github.com&utm_medium=referral&utm_campaign=vision_agents)
1615
2. **Cartesia Account**: Get your API key from [Cartesia](https://cartesia.ai/?utm_medium=partner&utm_source=getstream)
17-
3. **Python 3.10+**: Required for running the example
16+
3. **OpenAI Account**: Set an `OPENAI_API_KEY` for the example LLM.
17+
4. **Python 3.10+**: Required for running the example
1818

1919
## Installation
2020

@@ -31,7 +31,7 @@ You can use your preferred package manager, but we recommend [`uv`](https://docs
3131
```
3232

3333
3. **Set up environment variables:**
34-
Rename `env.example` to `.env` and fill in your actual credentials.
34+
Create a `.env` file with `STREAM_API_KEY`, `STREAM_API_SECRET`, `CARTESIA_API_KEY`, and `OPENAI_API_KEY`.
3535

3636
## Usage
3737

@@ -40,3 +40,5 @@ Run the example:
4040
```bash
4141
uv run main.py run
4242
```
43+
44+
Join the generated call, speak into your microphone, and the bot should answer out loud.

plugins/cartesia/example/main.py

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
#!/usr/bin/env python3
22
"""
3-
Example: Text-to-Speech with Cartesia using Agent class
3+
Example: Speech-to-Text and Text-to-Speech with Cartesia using Agent class
44
55
This minimal example shows how to:
6-
1. Create an Agent with TTS capabilities
6+
1. Create an Agent with Cartesia STT and TTS
77
2. Join a Stream video call
8-
3. Greet users when they join
8+
3. Greet users and respond to spoken input
99
10-
Run it, join the call in your browser, and hear the bot greet you 🗣️
10+
Run it, join the call in your browser, and speak to the bot.
1111
1212
Usage::
13-
python main.py
13+
uv run main.py run
1414
1515
The script looks for the following env vars (see `env.example`):
1616
STREAM_API_KEY / STREAM_API_SECRET
1717
CARTESIA_API_KEY
18+
OPENAI_API_KEY
1819
"""
1920

21+
import asyncio
2022
import logging
2123

2224
from dotenv import load_dotenv
@@ -31,11 +33,15 @@
3133

3234

3335
async def create_agent(**kwargs) -> Agent:
34-
# Create agent with TTS
36+
"""Create an agent with Cartesia STT and TTS."""
3537
agent = Agent(
3638
edge=getstream.Edge(),
37-
agent_user=User(name="TTS Bot", id="agent"),
38-
instructions="I'm a TTS bot that greets users when they join.",
39+
agent_user=User(name="Cartesia Voice Bot", id="agent"),
40+
instructions=(
41+
"You're a helpful voice AI assistant. "
42+
"Keep replies short and conversational."
43+
),
44+
stt=cartesia.STT(),
3945
llm=openai.LLM(model="gpt-4o-mini"),
4046
tts=cartesia.TTS(),
4147
)
@@ -44,12 +50,16 @@ async def create_agent(**kwargs) -> Agent:
4450

4551

4652
async def join_call(agent: Agent, call_type: str, call_id: str, **kwargs) -> None:
47-
# Create a call
4853
call = await agent.create_call(call_type, call_id)
4954

50-
# Join call and wait
55+
logger.info("Starting Cartesia STT/TTS voice bot")
56+
5157
async with agent.join(call):
52-
await agent.simple_response("tell me something interesting in a short sentence")
58+
logger.info("Joined call")
59+
await asyncio.sleep(3)
60+
await agent.simple_response(
61+
"Hello! I'm listening. What would you like to talk about?"
62+
)
5363
await agent.finish()
5464

5565

plugins/cartesia/example/narrator-example.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from vision_agents.core import Runner
2525
from vision_agents.core.agents import Agent, AgentLauncher
2626
from vision_agents.core.edge.types import User
27-
from vision_agents.plugins import cartesia, deepgram, getstream, openai
27+
from vision_agents.plugins import cartesia, getstream, openai
2828

2929
logger = logging.getLogger(__name__)
3030

@@ -37,7 +37,7 @@ async def create_agent(**kwargs) -> Agent:
3737
edge=getstream.Edge(),
3838
agent_user=User(name="Narrator", id="agent"),
3939
instructions="You're the narrator of a story. When you're given a topic start narrating a story and make heavy use of the audio markup tags to customize the speech output that are described in @sonic3-info.md.",
40-
stt=deepgram.STT(),
40+
stt=cartesia.STT(),
4141
llm=openai.LLM(model="gpt-4o-mini"),
4242
tts=cartesia.TTS(),
4343
)

plugins/cartesia/example/pyproject.toml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@ dependencies = [
99
"vision-agents-plugins-cartesia",
1010
"vision-agents-plugins-getstream",
1111
"vision-agents-plugins-openai",
12-
"vision-agents-plugins-deepgram",
1312
]
1413

1514
[tool.uv.sources]
16-
vision-agents = { editable = true }
17-
vision-agents-plugins-cartesia = { editable = true }
18-
vision-agents-plugins-getstream = { editable = true }
19-
vision-agents-plugins-openai = { editable = true }
20-
vision-agents-plugins-deepgram = { editable = true }
15+
"vision-agents" = { path = "../../../agents-core", editable = true }
16+
"vision-agents-plugins-cartesia" = { path = "..", editable = true }
17+
"vision-agents-plugins-getstream" = { path = "../../getstream", editable = true }
18+
"vision-agents-plugins-openai" = { path = "../../openai", editable = true }

plugins/cartesia/pyproject.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@ build-backend = "hatchling.build"
55
[project]
66
name = "vision-agents-plugins-cartesia"
77
dynamic = ["version"]
8-
description = "Cartesia TTS integration for Vision Agents"
8+
description = "Cartesia STT and TTS integration for Vision Agents"
99
readme = "README.md"
10-
keywords = ["cartesia", "TTS", "text-to-speech", "AI", "voice agents", "agents"]
10+
keywords = ["cartesia", "STT", "TTS", "speech-to-text", "text-to-speech", "AI", "voice agents", "agents"]
1111
requires-python = ">=3.10"
1212
license = "MIT"
1313
dependencies = [
1414
"vision-agents",
1515
"cartesia>=3.0.2,<3.1",
16+
"websockets>=15.0.1,<16",
1617
]
1718

1819
[project.urls]

0 commit comments

Comments
 (0)