livekit-plugins-chatfx 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_chatfx-0.1.0/.gitignore +4 -0
- livekit_plugins_chatfx-0.1.0/PKG-INFO +132 -0
- livekit_plugins_chatfx-0.1.0/README.md +113 -0
- livekit_plugins_chatfx-0.1.0/livekit/plugins/chatfx/__init__.py +37 -0
- livekit_plugins_chatfx-0.1.0/livekit/plugins/chatfx/avatar.py +624 -0
- livekit_plugins_chatfx-0.1.0/livekit/plugins/chatfx/log.py +3 -0
- livekit_plugins_chatfx-0.1.0/livekit/plugins/chatfx/py.typed +0 -0
- livekit_plugins_chatfx-0.1.0/livekit/plugins/chatfx/version.py +1 -0
- livekit_plugins_chatfx-0.1.0/pyproject.toml +34 -0
- livekit_plugins_chatfx-0.1.0/tests/test_avatar.py +579 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: livekit-plugins-chatfx
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: ChatFX Avatar for LiveKit Agents: a real-time talking face for your voice agent
|
|
5
|
+
Project-URL: Homepage, https://chatfx.com/avatar/
|
|
6
|
+
Project-URL: Documentation, https://chatfx.com/support/avatar-connect/
|
|
7
|
+
Author-email: "ChatRep, Inc." <service@chatfx.com>
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
Keywords: agents,avatar,chatfx,livekit,realtime,voice
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Topic :: Multimedia :: Video
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Requires-Dist: aiohttp>=3.9
|
|
16
|
+
Requires-Dist: livekit-agents>=1.2
|
|
17
|
+
Requires-Dist: pillow>=10.1
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# ChatFX Avatar for LiveKit Agents
|
|
21
|
+
|
|
22
|
+
A real-time talking face for your LiveKit voice agent. The avatar joins your agent's LiveKit Cloud room as one more
|
|
23
|
+
participant, takes your agent's voice and speaks it with its lips in time, shown as your agent. You keep your own
|
|
24
|
+
listening, AI and voice; ChatFX adds the face, billed by the minute.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install livekit-plugins-chatfx
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Requires Python 3.10+ and `livekit-agents` 1.2 or newer.
|
|
33
|
+
|
|
34
|
+
## Add your key
|
|
35
|
+
|
|
36
|
+
Create a key under **API keys** at [avatar.chatfx.com](https://avatar.chatfx.com). Then add it to your voice agent's secrets
|
|
37
|
+
at LiveKit, named exactly `CHATFX_AVATAR_API_KEY`. In your agent's folder:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
lk agent update-secrets --secrets "CHATFX_AVATAR_API_KEY=cfx_..."
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Running your agent on your own server instead? Add the key to that server's environment variables, with the same name.
|
|
44
|
+
|
|
45
|
+
Your agent also needs `LIVEKIT_URL`, `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET`, which it already has. They never leave your
|
|
46
|
+
server.
|
|
47
|
+
|
|
48
|
+
## Use it
|
|
49
|
+
|
|
50
|
+
In your agent's entrypoint, after you make the `AgentSession` and before `session.start()`:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from livekit.plugins import chatfx
|
|
54
|
+
|
|
55
|
+
avatar = chatfx.AvatarSession(avatar_id="chatfx-lois") # copy the id from the Avatars page
|
|
56
|
+
await avatar.start(session, room=ctx.room)
|
|
57
|
+
|
|
58
|
+
await session.start(agent=MyAgent(), room=ctx.room)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
That's all the code. When the job ends, the session ends too, so billing stops. To end it earlier, call
|
|
62
|
+
`await avatar.aclose()`.
|
|
63
|
+
|
|
64
|
+
## What it does for you
|
|
65
|
+
|
|
66
|
+
- **Shows a waiting picture, with nothing to add to your page.** The moment a call starts, your agent shows the avatar's picture
|
|
67
|
+
as its own video, with "Video starting..." on it, and the live face takes over when it's ready. Any page that shows the
|
|
68
|
+
agent's video gets this.
|
|
69
|
+
- **Greets with the face.** `start()` waits up to 10 seconds for the face, so your agent's first words come with it.
|
|
70
|
+
- **Starts by voice, over the picture, if the face is late.** The voice moves to the face between replies, so a sentence is never split.
|
|
71
|
+
- **Never depends on the face.** If the face can't come, or leaves mid-call, your agent carries on by voice.
|
|
72
|
+
- **Keeps trying** while a GPU wakes or is busy, for up to 5 minutes, and stops at once on a refusal more tries won't fix.
|
|
73
|
+
- **Stops forgotten calls**, so they don't use your minutes: after 2 minutes with nobody talking, 2 minutes after the visitor
|
|
74
|
+
leaves (long enough for a page reload), or at 1 hour.
|
|
75
|
+
- **Can't go deaf.** If the face's "finished talking" message is late, the plugin ends the reply once the sound has run out,
|
|
76
|
+
so your agent hears the next question.
|
|
77
|
+
|
|
78
|
+
## Options
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
chatfx.AvatarSession(
|
|
82
|
+
avatar_id="chatfx-lois",
|
|
83
|
+
api_key=None, # defaults to CHATFX_AVATAR_API_KEY
|
|
84
|
+
api_url=None, # defaults to https://api.chatfx.com
|
|
85
|
+
avatar_participant_identity="chatfx-avatar",
|
|
86
|
+
avatar_participant_name="ChatFX",
|
|
87
|
+
face_first_seconds=10.0, # how long start() waits for the face
|
|
88
|
+
start_timeout=300.0, # how long to keep trying while a GPU wakes
|
|
89
|
+
quiet_seconds=120.0, # end the call after this long with nobody talking (None: never)
|
|
90
|
+
visitor_gone_seconds=120.0, # end the call this long after the last visitor leaves (None: never)
|
|
91
|
+
longest_call_seconds=3600.0, # end the call at this length (None: never)
|
|
92
|
+
end_call_when_idle=True, # False: only the avatar leaves, and your agent carries on by voice
|
|
93
|
+
waiting_picture=True, # show the avatar's picture until the live face is ready
|
|
94
|
+
waiting_text="Video starting...", # the words on it, in your language (None: no words)
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`avatar.start()` also takes `livekit_url`, `livekit_api_key` and `livekit_api_secret` if you'd rather not use the settings.
|
|
99
|
+
|
|
100
|
+
We recommend `"interruption": {"min_words": 1}` in your session's turn handling. The avatar's sound can't pause and carry on,
|
|
101
|
+
so a false alarm would otherwise cut a reply off for good.
|
|
102
|
+
|
|
103
|
+
## Optional: make the face appear sooner
|
|
104
|
+
|
|
105
|
+
The plugin starts waking the GPU as soon as a call begins, which takes about 11 seconds. To start even earlier, call `warm()` from your website's server when a visitor
|
|
106
|
+
is about to start a call, and again every 20 seconds while they get ready. It's free. Your website's server then needs the key
|
|
107
|
+
in its environment variables too. Never put the key in a web page.
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
await chatfx.warm()
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Or without Python:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
curl -X POST https://api.chatfx.com/v1/warm -H "Authorization: Bearer $CHATFX_AVATAR_API_KEY"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## If you build your own call screen
|
|
120
|
+
|
|
121
|
+
Your agent's participant attribute `chatfx-face` says where the face is: `waking`, `voice`, `on` or `off`. In the agent,
|
|
122
|
+
`avatar.face_status` says the same. You don't need either to get the waiting picture.
|
|
123
|
+
|
|
124
|
+
## When there's no face
|
|
125
|
+
|
|
126
|
+
A refusal doesn't stop the call. The log says why, and `avatar.failure` is a `chatfx.ChatFXException` with the API's `code`
|
|
127
|
+
(for example `invalid_api_key`, `avatar_not_found`, `premium_avatar`, `out_of_minutes`) and a plain message. A missing key or
|
|
128
|
+
missing LiveKit setting raises right away, so you find it while setting up.
|
|
129
|
+
|
|
130
|
+
## Docs
|
|
131
|
+
|
|
132
|
+
[Connecting your agent](https://chatfx.com/support/avatar-connect/) · [Building avatars](https://chatfx.com/support/avatar-builder/) · [Minutes and plans](https://chatfx.com/support/avatar-billing/)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# ChatFX Avatar for LiveKit Agents
|
|
2
|
+
|
|
3
|
+
A real-time talking face for your LiveKit voice agent. The avatar joins your agent's LiveKit Cloud room as one more
|
|
4
|
+
participant, takes your agent's voice and speaks it with its lips in time, shown as your agent. You keep your own
|
|
5
|
+
listening, AI and voice; ChatFX adds the face, billed by the minute.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install livekit-plugins-chatfx
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Requires Python 3.10+ and `livekit-agents` 1.2 or newer.
|
|
14
|
+
|
|
15
|
+
## Add your key
|
|
16
|
+
|
|
17
|
+
Create a key under **API keys** at [avatar.chatfx.com](https://avatar.chatfx.com). Then add it to your voice agent's secrets
|
|
18
|
+
at LiveKit, named exactly `CHATFX_AVATAR_API_KEY`. In your agent's folder:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
lk agent update-secrets --secrets "CHATFX_AVATAR_API_KEY=cfx_..."
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Running your agent on your own server instead? Add the key to that server's environment variables, with the same name.
|
|
25
|
+
|
|
26
|
+
Your agent also needs `LIVEKIT_URL`, `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET`, which it already has. They never leave your
|
|
27
|
+
server.
|
|
28
|
+
|
|
29
|
+
## Use it
|
|
30
|
+
|
|
31
|
+
In your agent's entrypoint, after you make the `AgentSession` and before `session.start()`:
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from livekit.plugins import chatfx
|
|
35
|
+
|
|
36
|
+
avatar = chatfx.AvatarSession(avatar_id="chatfx-lois") # copy the id from the Avatars page
|
|
37
|
+
await avatar.start(session, room=ctx.room)
|
|
38
|
+
|
|
39
|
+
await session.start(agent=MyAgent(), room=ctx.room)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
That's all the code. When the job ends, the session ends too, so billing stops. To end it earlier, call
|
|
43
|
+
`await avatar.aclose()`.
|
|
44
|
+
|
|
45
|
+
## What it does for you
|
|
46
|
+
|
|
47
|
+
- **Shows a waiting picture, with nothing to add to your page.** The moment a call starts, your agent shows the avatar's picture
|
|
48
|
+
as its own video, with "Video starting..." on it, and the live face takes over when it's ready. Any page that shows the
|
|
49
|
+
agent's video gets this.
|
|
50
|
+
- **Greets with the face.** `start()` waits up to 10 seconds for the face, so your agent's first words come with it.
|
|
51
|
+
- **Starts by voice, over the picture, if the face is late.** The voice moves to the face between replies, so a sentence is never split.
|
|
52
|
+
- **Never depends on the face.** If the face can't come, or leaves mid-call, your agent carries on by voice.
|
|
53
|
+
- **Keeps trying** while a GPU wakes or is busy, for up to 5 minutes, and stops at once on a refusal more tries won't fix.
|
|
54
|
+
- **Stops forgotten calls**, so they don't use your minutes: after 2 minutes with nobody talking, 2 minutes after the visitor
|
|
55
|
+
leaves (long enough for a page reload), or at 1 hour.
|
|
56
|
+
- **Can't go deaf.** If the face's "finished talking" message is late, the plugin ends the reply once the sound has run out,
|
|
57
|
+
so your agent hears the next question.
|
|
58
|
+
|
|
59
|
+
## Options
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
chatfx.AvatarSession(
|
|
63
|
+
avatar_id="chatfx-lois",
|
|
64
|
+
api_key=None, # defaults to CHATFX_AVATAR_API_KEY
|
|
65
|
+
api_url=None, # defaults to https://api.chatfx.com
|
|
66
|
+
avatar_participant_identity="chatfx-avatar",
|
|
67
|
+
avatar_participant_name="ChatFX",
|
|
68
|
+
face_first_seconds=10.0, # how long start() waits for the face
|
|
69
|
+
start_timeout=300.0, # how long to keep trying while a GPU wakes
|
|
70
|
+
quiet_seconds=120.0, # end the call after this long with nobody talking (None: never)
|
|
71
|
+
visitor_gone_seconds=120.0, # end the call this long after the last visitor leaves (None: never)
|
|
72
|
+
longest_call_seconds=3600.0, # end the call at this length (None: never)
|
|
73
|
+
end_call_when_idle=True, # False: only the avatar leaves, and your agent carries on by voice
|
|
74
|
+
waiting_picture=True, # show the avatar's picture until the live face is ready
|
|
75
|
+
waiting_text="Video starting...", # the words on it, in your language (None: no words)
|
|
76
|
+
)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`avatar.start()` also takes `livekit_url`, `livekit_api_key` and `livekit_api_secret` if you'd rather not use the settings.
|
|
80
|
+
|
|
81
|
+
We recommend `"interruption": {"min_words": 1}` in your session's turn handling. The avatar's sound can't pause and carry on,
|
|
82
|
+
so a false alarm would otherwise cut a reply off for good.
|
|
83
|
+
|
|
84
|
+
## Optional: make the face appear sooner
|
|
85
|
+
|
|
86
|
+
The plugin starts waking the GPU as soon as a call begins, which takes about 11 seconds. To start even earlier, call `warm()` from your website's server when a visitor
|
|
87
|
+
is about to start a call, and again every 20 seconds while they get ready. It's free. Your website's server then needs the key
|
|
88
|
+
in its environment variables too. Never put the key in a web page.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
await chatfx.warm()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Or without Python:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
curl -X POST https://api.chatfx.com/v1/warm -H "Authorization: Bearer $CHATFX_AVATAR_API_KEY"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## If you build your own call screen
|
|
101
|
+
|
|
102
|
+
Your agent's participant attribute `chatfx-face` says where the face is: `waking`, `voice`, `on` or `off`. In the agent,
|
|
103
|
+
`avatar.face_status` says the same. You don't need either to get the waiting picture.
|
|
104
|
+
|
|
105
|
+
## When there's no face
|
|
106
|
+
|
|
107
|
+
A refusal doesn't stop the call. The log says why, and `avatar.failure` is a `chatfx.ChatFXException` with the API's `code`
|
|
108
|
+
(for example `invalid_api_key`, `avatar_not_found`, `premium_avatar`, `out_of_minutes`) and a plain message. A missing key or
|
|
109
|
+
missing LiveKit setting raises right away, so you find it while setting up.
|
|
110
|
+
|
|
111
|
+
## Docs
|
|
112
|
+
|
|
113
|
+
[Connecting your agent](https://chatfx.com/support/avatar-connect/) · [Building avatars](https://chatfx.com/support/avatar-builder/) · [Minutes and plans](https://chatfx.com/support/avatar-billing/)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""ChatFX Avatar for LiveKit Agents.
|
|
2
|
+
|
|
3
|
+
A real-time talking face for your voice agent. The avatar joins your agent's LiveKit room as one more participant, takes
|
|
4
|
+
your agent's voice and speaks it with its lips in time, shown as your agent.
|
|
5
|
+
|
|
6
|
+
from livekit.plugins import chatfx
|
|
7
|
+
|
|
8
|
+
avatar = chatfx.AvatarSession(avatar_id="chatfx-lois") # your key in CHATFX_AVATAR_API_KEY
|
|
9
|
+
await avatar.start(session, room=ctx.room)
|
|
10
|
+
|
|
11
|
+
Docs: https://chatfx.com/support/avatar-connect/
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from livekit.agents import Plugin
|
|
15
|
+
|
|
16
|
+
from .avatar import AvatarSession, ChatFXException, warm
|
|
17
|
+
from .log import logger
|
|
18
|
+
from .version import __version__
|
|
19
|
+
|
|
20
|
+
__all__ = ["AvatarSession", "ChatFXException", "warm", "__version__"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ChatFXPlugin(Plugin):
|
|
24
|
+
def __init__(self) -> None:
|
|
25
|
+
super().__init__(__name__, __version__, __package__, logger)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Plugin.register_plugin(ChatFXPlugin())
|
|
29
|
+
|
|
30
|
+
# Cleanup docs of unexported modules
|
|
31
|
+
_module = dir()
|
|
32
|
+
NOT_IN_ALL = [m for m in _module if m not in __all__]
|
|
33
|
+
|
|
34
|
+
__pdoc__ = {}
|
|
35
|
+
|
|
36
|
+
for n in NOT_IN_ALL:
|
|
37
|
+
__pdoc__[n] = False
|