Skip to content

Commit 7ae39a2

Browse files
Implementation for livekit-plugins-neuphonic (TTS provider) (#1612)
Co-authored-by: Jayesh Parmar <60539217+jayeshp19@users.noreply.github.com>
1 parent 5633b73 commit 7ae39a2

File tree

16 files changed

+649
-1
lines changed

16 files changed

+649
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ We've partnered with OpenAI on a new `MultimodalAgent` API in the Agents framewo
102102
| Deepgram | livekit-plugins-deepgram || | [deepgram.TTS()](https://docs.livekit.io/python/livekit/plugins/deepgram/index.html#livekit.plugins.deepgram.TTS) |
103103
| Play.ai | livekit-plugins-playai ||| [playai.TTS()](https://docs.livekit.io/python/livekit/plugins/playai/index.html#livekit.plugins.playai.TTS) |
104104
| Rime | livekit-plugins-rime || | [rime.TTS()](https://docs.livekit.io/python/livekit/plugins/rime/index.html#livekit.plugins.rime.TTS) |
105+
| Neuphonic | livekit-plugins-neuphonic ||| neuphonic.TTS() |
105106
| AWS Polly | livekit-plugins-aws || | [aws.TTS()](https://docs.livekit.io/python/livekit/plugins/aws/index.html#livekit.plugins.aws.TTS) |
106107

107108
### Other plugins
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import asyncio
2+
import logging
3+
4+
from dotenv import load_dotenv
5+
from livekit import rtc
6+
from livekit.agents import AutoSubscribe, JobContext, WorkerOptions, cli
7+
from livekit.plugins import neuphonic
8+
9+
load_dotenv()
10+
11+
logger = logging.getLogger("neuphonic-tts-demo")
12+
logger.setLevel(logging.INFO)
13+
14+
15+
async def entrypoint(job: JobContext):
16+
logger.info("starting tts example agent")
17+
18+
SAMPLE_RATE = 22050
19+
NUM_CHANNELS = 1
20+
21+
tts = neuphonic.TTS(
22+
# voice_id=<uuid>,
23+
sample_rate=SAMPLE_RATE # defaults to 22050
24+
)
25+
26+
source = rtc.AudioSource(SAMPLE_RATE, NUM_CHANNELS)
27+
track = rtc.LocalAudioTrack.create_audio_track("agent-mic", source)
28+
options = rtc.TrackPublishOptions()
29+
options.source = rtc.TrackSource.SOURCE_MICROPHONE
30+
31+
await job.connect(auto_subscribe=AutoSubscribe.SUBSCRIBE_NONE)
32+
publication = await job.room.local_participant.publish_track(track, options)
33+
await publication.wait_for_subscription()
34+
35+
stream = tts.stream()
36+
37+
async def _playback_task():
38+
async for audio in stream:
39+
await source.capture_frame(audio.frame)
40+
41+
task = asyncio.create_task(_playback_task())
42+
43+
text = "Hello from Neuphonic. You have just successfully run the example!"
44+
45+
# split into two word chunks to simulate LLM streaming
46+
words = text.split()
47+
for i in range(0, len(words), 2):
48+
chunk = " ".join(words[i : i + 2])
49+
if chunk:
50+
logger.info(f'pushing chunk: "{chunk} "')
51+
stream.push_text(chunk + " ")
52+
53+
# Mark end of input segment
54+
stream.flush()
55+
stream.end_input()
56+
await asyncio.gather(task)
57+
58+
59+
if __name__ == "__main__":
60+
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))

livekit-plugins/install_local.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ pip install \
2222
"${SCRIPT_DIR}/livekit-plugins-turn-detector" \
2323
"${SCRIPT_DIR}/livekit-plugins-rime" \
2424
"${SCRIPT_DIR}/livekit-plugins-aws" \
25-
"${SCRIPT_DIR}/livekit-plugins-speechmatics"
25+
"${SCRIPT_DIR}/livekit-plugins-speechmatics" \
26+
"${SCRIPT_DIR}/livekit-plugins-neuphonic"

livekit-plugins/install_plugins_editable.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@ pip install -e ./livekit-plugins-llama-index --config-settings editable_mode=str
2323
pip install -e ./livekit-plugins-turn-detector --config-settings editable_mode=strict
2424
pip install -e ./livekit-plugins-silero --config-settings editable_mode=strict
2525
pip install -e ./livekit-plugins-speechmatics --config-settings editable_mode=strict
26+
pip install -e ./livekit-plugins-neuphonic --config-settings editable_mode=strict
2627
pip install -e ./livekit-plugins-browser --config-settings editable_mode=strict
2728

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# livekit-plugins-neuphonic
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# LiveKit Plugins Neuphonic
2+
3+
Agent Framework plugin for voice synthesis with [Neuphonic](https://neuphonic.com) API.
4+
5+
## Installation
6+
7+
```bash
8+
pip install livekit-plugins-neuphonic
9+
```
10+
11+
## Pre-requisites
12+
13+
You'll need an API key from Neuphonic. It can be set as an environment variable: `NEUPHONIC_API_TOKEN`
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2023 LiveKit, Inc.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from .tts import TTS, ChunkedStream
16+
from .version import __version__
17+
18+
__all__ = ["TTS", "ChunkedStream", "__version__"]
19+
20+
from livekit.agents import Plugin
21+
22+
from .log import logger
23+
24+
25+
class NeuphonicPlugin(Plugin):
26+
def __init__(self):
27+
super().__init__(__name__, __version__, __package__, logger)
28+
29+
30+
Plugin.register_plugin(NeuphonicPlugin())
31+
32+
# Cleanup docs of unexported modules
33+
_module = dir()
34+
NOT_IN_ALL = [m for m in _module if m not in __all__]
35+
36+
__pdoc__ = {}
37+
38+
for n in NOT_IN_ALL:
39+
__pdoc__[n] = False
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import logging
2+
3+
logger = logging.getLogger("livekit.plugins.neuphonic")
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from typing import Literal
2+
3+
TTSEncodings = Literal[
4+
"pcm_linear",
5+
"pcm_mulaw",
6+
]
7+
8+
TTSModels = Literal["neu-fast", "neu-hq"]
9+
10+
TTSLangCodes = Literal["en", "nl", "es", "de", "hi", "en-hi", "ar"]

livekit-plugins/livekit-plugins-neuphonic/livekit/plugins/neuphonic/py.typed

Whitespace-only changes.

0 commit comments

Comments
 (0)