livekit-plugins-chariot 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.
- livekit_plugins_chariot-0.1.0/PKG-INFO +54 -0
- livekit_plugins_chariot-0.1.0/README.md +32 -0
- livekit_plugins_chariot-0.1.0/livekit/plugins/chariot/__init__.py +62 -0
- livekit_plugins_chariot-0.1.0/livekit/plugins/chariot/_utils.py +116 -0
- livekit_plugins_chariot-0.1.0/livekit/plugins/chariot/log.py +3 -0
- livekit_plugins_chariot-0.1.0/livekit/plugins/chariot/models.py +19 -0
- livekit_plugins_chariot-0.1.0/livekit/plugins/chariot/py.typed +0 -0
- livekit_plugins_chariot-0.1.0/livekit/plugins/chariot/stt.py +636 -0
- livekit_plugins_chariot-0.1.0/livekit/plugins/chariot/tts.py +596 -0
- livekit_plugins_chariot-0.1.0/livekit/plugins/chariot/version.py +15 -0
- livekit_plugins_chariot-0.1.0/pyproject.toml +39 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: livekit-plugins-chariot
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Agent Framework plugin for Chariot speech-to-text and text-to-speech.
|
|
5
|
+
Project-URL: Homepage, https://chariot.in
|
|
6
|
+
Project-URL: Documentation, https://docs.chariot.in/api-reference/introduction
|
|
7
|
+
Project-URL: Source, https://github.com/Chariot-AI/livekit-agents/tree/feat/chariot-plugin/livekit-plugins/livekit-plugins-chariot
|
|
8
|
+
Project-URL: Pull request, https://github.com/livekit/agents/pull/8560
|
|
9
|
+
Author: Chariot
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
Keywords: ai,audio,chariot,indian-languages,livekit,realtime,speech-to-text,stt,text-to-speech,tts,voice
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
19
|
+
Requires-Python: >=3.10.0
|
|
20
|
+
Requires-Dist: livekit-agents>=1.8.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Chariot plugin for LiveKit Agents
|
|
24
|
+
|
|
25
|
+
Support for speech-to-text and text-to-speech with [Chariot](https://chariot.in/) in LiveKit Agents: English and Indian languages, including code-mixed speech such as Hinglish.
|
|
26
|
+
|
|
27
|
+
See the [Chariot docs](https://docs.chariot.in/api-reference/introduction) for the API, models and voices. This plugin is proposed for LiveKit Agents in [livekit/agents#8560](https://github.com/livekit/agents/pull/8560); this package will move to LiveKit once it is merged.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install livekit-plugins-chariot
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Pre-requisites
|
|
36
|
+
|
|
37
|
+
You'll need an API key from Chariot. It can be set as an environment variable: `CHARIOT_API_KEY`. You can create one [here](https://platform.chariot.in).
|
|
38
|
+
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from livekit.agents import AgentSession
|
|
43
|
+
from livekit.plugins import chariot
|
|
44
|
+
|
|
45
|
+
session = AgentSession(
|
|
46
|
+
stt=chariot.STT(language="hi"), # omit the language to detect it
|
|
47
|
+
tts=chariot.TTS(voice="bac7d666-094d-4698-91fa-741d60fce662"), # Matt
|
|
48
|
+
# ... llm, etc.
|
|
49
|
+
)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The STT transcribes English, Hindi, Bengali, Gujarati, Kannada, Malayalam, Marathi, Odia, Punjabi, Sanskrit, Tamil and Telugu. By default each transcript is finalized when the agent's turn detection ends the user's turn; pass `server_vad={}` to let Chariot's voice detection split utterances instead.
|
|
53
|
+
|
|
54
|
+
Any TTS voice speaks every supported language: the language of the audio follows the text. List the voices with `GET https://api.chariot.in/v1/voices`. An interrupted reply is cancelled on the server and its connection is kept for the next one.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Chariot plugin for LiveKit Agents
|
|
2
|
+
|
|
3
|
+
Support for speech-to-text and text-to-speech with [Chariot](https://chariot.in/) in LiveKit Agents: English and Indian languages, including code-mixed speech such as Hinglish.
|
|
4
|
+
|
|
5
|
+
See the [Chariot docs](https://docs.chariot.in/api-reference/introduction) for the API, models and voices. This plugin is proposed for LiveKit Agents in [livekit/agents#8560](https://github.com/livekit/agents/pull/8560); this package will move to LiveKit once it is merged.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install livekit-plugins-chariot
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Pre-requisites
|
|
14
|
+
|
|
15
|
+
You'll need an API key from Chariot. It can be set as an environment variable: `CHARIOT_API_KEY`. You can create one [here](https://platform.chariot.in).
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from livekit.agents import AgentSession
|
|
21
|
+
from livekit.plugins import chariot
|
|
22
|
+
|
|
23
|
+
session = AgentSession(
|
|
24
|
+
stt=chariot.STT(language="hi"), # omit the language to detect it
|
|
25
|
+
tts=chariot.TTS(voice="bac7d666-094d-4698-91fa-741d60fce662"), # Matt
|
|
26
|
+
# ... llm, etc.
|
|
27
|
+
)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The STT transcribes English, Hindi, Bengali, Gujarati, Kannada, Malayalam, Marathi, Odia, Punjabi, Sanskrit, Tamil and Telugu. By default each transcript is finalized when the agent's turn detection ends the user's turn; pass `server_vad={}` to let Chariot's voice detection split utterances instead.
|
|
31
|
+
|
|
32
|
+
Any TTS voice speaks every supported language: the language of the audio follows the text. List the voices with `GET https://api.chariot.in/v1/voices`. An interrupted reply is cancelled on the server and its connection is kept for the next one.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Copyright 2026 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
|
+
"""Chariot plugin for LiveKit Agents
|
|
16
|
+
|
|
17
|
+
Support for speech-to-text and text-to-speech with [Chariot](https://chariot.in/), for English
|
|
18
|
+
and Indian languages, including code-mixed speech.
|
|
19
|
+
|
|
20
|
+
See https://docs.chariot.in/api-reference/introduction for more information.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from .models import STTLanguages, STTModels, STTModes, STTStyles, TTSModels
|
|
24
|
+
from .stt import STT, SpeechStream, VADOptions
|
|
25
|
+
from .tts import TTS, ChunkedStream, SynthesizeStream
|
|
26
|
+
from .version import __version__
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"STT",
|
|
30
|
+
"SpeechStream",
|
|
31
|
+
"VADOptions",
|
|
32
|
+
"TTS",
|
|
33
|
+
"ChunkedStream",
|
|
34
|
+
"SynthesizeStream",
|
|
35
|
+
"STTLanguages",
|
|
36
|
+
"STTModels",
|
|
37
|
+
"STTModes",
|
|
38
|
+
"STTStyles",
|
|
39
|
+
"TTSModels",
|
|
40
|
+
"__version__",
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
from livekit.agents import Plugin
|
|
44
|
+
|
|
45
|
+
from .log import logger
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class ChariotPlugin(Plugin):
|
|
49
|
+
def __init__(self) -> None:
|
|
50
|
+
super().__init__(__name__, __version__, __package__, logger)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
Plugin.register_plugin(ChariotPlugin())
|
|
54
|
+
|
|
55
|
+
# Cleanup docs of unexported modules
|
|
56
|
+
_module = dir()
|
|
57
|
+
NOT_IN_ALL = [m for m in _module if m not in __all__]
|
|
58
|
+
|
|
59
|
+
__pdoc__ = {}
|
|
60
|
+
|
|
61
|
+
for n in NOT_IN_ALL:
|
|
62
|
+
__pdoc__[n] = False
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Copyright 2026 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 __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
import os
|
|
19
|
+
|
|
20
|
+
import aiohttp
|
|
21
|
+
|
|
22
|
+
from livekit.agents import APIConnectionError, APIError, APIStatusError
|
|
23
|
+
|
|
24
|
+
from .version import __version__
|
|
25
|
+
|
|
26
|
+
BASE_URL = "https://api.chariot.in"
|
|
27
|
+
API_KEY_HEADER = "chariotai-api-key"
|
|
28
|
+
USER_AGENT = f"LiveKit Agents Chariot Plugin/{__version__}"
|
|
29
|
+
|
|
30
|
+
# The WebSocket close codes the API uses, besides 1000 (normal).
|
|
31
|
+
CLOSE_POLICY = 1008 # invalid key or parameters, idle timeout, a backlog limit
|
|
32
|
+
CLOSE_SERVER_ERROR = 1011
|
|
33
|
+
CLOSE_NO_CREDITS = 4402
|
|
34
|
+
CLOSE_SESSION_LIMIT = 4413 # the session reached its maximum length
|
|
35
|
+
CLOSE_BUSY = 4429 # every concurrent session the plan allows is in use
|
|
36
|
+
|
|
37
|
+
# HTTP status for each WebSocket error code, so retries follow the usual 4xx/5xx rules.
|
|
38
|
+
_ERROR_STATUS = {
|
|
39
|
+
"bad_request": 400,
|
|
40
|
+
"unknown_context": 400,
|
|
41
|
+
"context_closing": 400,
|
|
42
|
+
"session_closing": 400,
|
|
43
|
+
"text_too_long": 400,
|
|
44
|
+
"insufficient_credits": 402,
|
|
45
|
+
"forbidden": 403,
|
|
46
|
+
"idle_timeout": 408,
|
|
47
|
+
"voice_unavailable": 422,
|
|
48
|
+
"context_limit": 429,
|
|
49
|
+
"concurrency_limit": 429,
|
|
50
|
+
"upstream_error": 502,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# 1008 reasons that a fresh connection clears, as opposed to a refusal it would repeat.
|
|
54
|
+
_TRANSIENT_POLICY_REASONS = ("idle", "pending audio", "pending commit")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def resolve_api_key(api_key: str | None) -> str:
|
|
58
|
+
api_key = api_key or os.environ.get("CHARIOT_API_KEY")
|
|
59
|
+
if not api_key:
|
|
60
|
+
raise ValueError("Chariot API key required. Set CHARIOT_API_KEY or provide api_key.")
|
|
61
|
+
return api_key
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def headers(api_key: str) -> dict[str, str]:
|
|
65
|
+
return {API_KEY_HEADER: api_key, "User-Agent": USER_AGENT}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def ws_base_url(base_url: str) -> str:
|
|
69
|
+
return base_url.replace("https://", "wss://", 1).replace("http://", "ws://", 1)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def error_event(event: dict) -> APIError:
|
|
73
|
+
"""An `error` message on a WebSocket.
|
|
74
|
+
|
|
75
|
+
A string `code` names a refused request on a connection that stays open. A numeric `code`
|
|
76
|
+
is the close code of a connection the server is about to close.
|
|
77
|
+
"""
|
|
78
|
+
code = event.get("code")
|
|
79
|
+
message = str(event.get("message") or "Chariot API error")
|
|
80
|
+
if isinstance(code, int):
|
|
81
|
+
return close_error(code, message)
|
|
82
|
+
return APIStatusError(
|
|
83
|
+
message, status_code=_ERROR_STATUS.get(code or "", 500), body=code or None
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def close_error(code: int | None, reason: str) -> APIError:
|
|
88
|
+
"""The error for a connection the server closed before the work was done."""
|
|
89
|
+
message = f"Chariot connection closed ({code}): {reason or 'no reason given'}"
|
|
90
|
+
if code == CLOSE_POLICY and reason.lower().startswith("unauthorized"):
|
|
91
|
+
return APIStatusError(message, status_code=401)
|
|
92
|
+
if code == CLOSE_NO_CREDITS:
|
|
93
|
+
return APIStatusError(message, status_code=402)
|
|
94
|
+
if code == CLOSE_BUSY:
|
|
95
|
+
return APIStatusError(message, status_code=429)
|
|
96
|
+
if code == CLOSE_POLICY and not any(r in reason.lower() for r in _TRANSIENT_POLICY_REASONS):
|
|
97
|
+
return APIStatusError(message, status_code=400)
|
|
98
|
+
return APIConnectionError(message)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
async def http_error(resp: aiohttp.ClientResponse, request_id: str | None = None) -> APIStatusError:
|
|
102
|
+
"""An error response from an HTTP endpoint, which carries `{"statusCode", "message"}`."""
|
|
103
|
+
text = await resp.text()
|
|
104
|
+
message = text
|
|
105
|
+
try:
|
|
106
|
+
body = json.loads(text)
|
|
107
|
+
if isinstance(body, dict) and body.get("message"):
|
|
108
|
+
message = str(body["message"])
|
|
109
|
+
except ValueError:
|
|
110
|
+
pass
|
|
111
|
+
return APIStatusError(
|
|
112
|
+
message or "Chariot API error",
|
|
113
|
+
status_code=resp.status,
|
|
114
|
+
request_id=request_id,
|
|
115
|
+
body=text or None,
|
|
116
|
+
)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
from typing import Literal
|
|
2
|
+
|
|
3
|
+
TTSModels = Literal["chariot-multilingual-v1", "chariot-v0"]
|
|
4
|
+
|
|
5
|
+
STTModels = Literal["chariot-1-asr-realtime"]
|
|
6
|
+
|
|
7
|
+
# Languages the speech-to-text model transcribes. Leave the language unset to detect it.
|
|
8
|
+
STTLanguages = Literal["en", "hi", "bn", "gu", "kn", "ml", "mr", "or", "pa", "sa", "ta", "te"]
|
|
9
|
+
|
|
10
|
+
# "balanced" favors latency. "high_accuracy" is more accurate (it writes numbers as digits,
|
|
11
|
+
# for example); its interim transcripts update less often.
|
|
12
|
+
STTModes = Literal["balanced", "high_accuracy"]
|
|
13
|
+
|
|
14
|
+
# "codemix" writes each word in the script it is usually written in, so English words in
|
|
15
|
+
# Hindi speech come out in Latin script. "native" writes everything in the language's script.
|
|
16
|
+
STTStyles = Literal["codemix", "native"]
|
|
17
|
+
|
|
18
|
+
# Mono 16-bit PCM rates the streaming API accepts.
|
|
19
|
+
STTSampleRates = Literal[8000, 16000, 22050, 24000, 32000, 44100, 48000]
|
|
File without changes
|