pipecat-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.
@@ -0,0 +1,9 @@
1
+ node_modules/
2
+ .env
3
+ .env.*
4
+ !.env.example
5
+ data/
6
+ *.log
7
+ dist/
8
+ .claude/
9
+ __pycache__/
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ - First release: `ChatFXVideoService`, a ChatFX Avatar face and voice for any Pipecat bot. Put it right after your TTS
6
+ service. Tested with Pipecat v1.15.0 and daily-python 0.37.0.
@@ -0,0 +1,24 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, ChatRep, Inc.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,117 @@
1
+ Metadata-Version: 2.5
2
+ Name: pipecat-chatfx
3
+ Version: 0.1.0
4
+ Summary: ChatFX Avatar for Pipecat: a real-time talking face for your Pipecat bot
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: BSD-2-Clause
9
+ License-File: LICENSE
10
+ Keywords: avatar,chatfx,daily,pipecat,realtime,video,voice
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Multimedia :: Video
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.10
16
+ Requires-Dist: aiohttp>=3.9
17
+ Requires-Dist: pipecat-ai[daily]>=1.8
18
+ Description-Content-Type: text/markdown
19
+
20
+ # ChatFX Avatar for Pipecat
21
+
22
+ A real-time talking face for your Pipecat bot. Your bot's voice goes to the avatar, and its face and voice come back,
23
+ drawn together so the lips match, as your bot's own video and audio. You keep your own listening, AI and voice; ChatFX
24
+ adds the face, billed by the minute.
25
+
26
+ Tested with Pipecat v1.15.0.
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ pip install pipecat-chatfx
32
+ ```
33
+
34
+ Requires Python 3.10+ and `pipecat-ai` 1.8 or newer (it brings `pipecat-ai[daily]`).
35
+
36
+ ## Add your keys
37
+
38
+ - `CHATFX_AVATAR_API_KEY`: create one under **API keys** at [avatar.chatfx.com](https://avatar.chatfx.com).
39
+ - `DAILY_API_KEY`: from your [Daily dashboard](https://dashboard.daily.co/developers). Running on Pipecat Cloud, you already
40
+ have one. The avatar meets your bot in a private Daily room in your account, made for each call and removed when it
41
+ ends, the way Pipecat's own Tavus service works.
42
+
43
+ Put both in your bot's environment (your `.env`, or your Pipecat Cloud secret set).
44
+
45
+ ## Use it
46
+
47
+ Put `ChatFXVideoService` right after your TTS service, and turn on your transport's video out at the avatar's size:
48
+
49
+ ```python
50
+ from pipecat_chatfx import ChatFXVideoService
51
+
52
+ avatar = ChatFXVideoService(avatar_id="chatfx-lois") # copy the id from the Avatars page
53
+
54
+ pipeline = Pipeline([
55
+ transport.input(),
56
+ stt,
57
+ user_aggregator,
58
+ llm,
59
+ tts,
60
+ avatar,
61
+ transport.output(),
62
+ assistant_aggregator,
63
+ ])
64
+ ```
65
+
66
+ ```python
67
+ TransportParams( # or DailyParams
68
+ audio_in_enabled=True,
69
+ audio_out_enabled=True,
70
+ video_out_enabled=True,
71
+ video_out_is_live=True,
72
+ video_out_width=912, # 912 x 512 landscape, 512 x 512 square, 384 x 512 portrait
73
+ video_out_height=512,
74
+ video_out_framerate=25,
75
+ )
76
+ ```
77
+
78
+ That's all the code. When your pipeline ends (or is cancelled when the visitor leaves), the avatar's session ends too, so
79
+ billing stops. Your page shows the bot's video as before: the avatar is the bot.
80
+
81
+ Step by step: [Connecting your agent: Pipecat](https://chatfx.com/support/avatar-connect/#pipecat). A full sample bot
82
+ (Deepgram, OpenAI, Cartesia) comes in this package's source download, in `examples/`: `uv run bot.py`, then open
83
+ http://localhost:7860/client.
84
+
85
+ ## What it does for you
86
+
87
+ - **Shows a waiting picture.** Until the live face is in, your bot's video is the avatar's picture with "Video starting..."
88
+ on it.
89
+ - **Greets with the face.** Your bot's first words wait up to 10 seconds for the face, so they come with it.
90
+ - **Never depends on the face.** If the face can't come, or leaves mid-call, your bot carries on with its own voice.
91
+ - **Stops at once when talked over.** An interruption stops the avatar mid-word.
92
+ - **Lets the last words finish.** At the end of a call, the avatar finishes its goodbye before it leaves.
93
+
94
+ ## Options
95
+
96
+ ```python
97
+ ChatFXVideoService(
98
+ avatar_id="chatfx-lois",
99
+ api_key=None, # defaults to CHATFX_AVATAR_API_KEY
100
+ daily_api_key=None, # defaults to DAILY_API_KEY
101
+ api_url=None, # defaults to https://api.chatfx.com
102
+ face_first_seconds=10.0, # how long the first words wait for the face
103
+ start_timeout=120.0, # how long to keep trying to start the avatar
104
+ waiting_picture=True, # show the avatar's picture until the live face is in
105
+ waiting_text="Video starting...", # the words on it, in your language (None: no words)
106
+ )
107
+ ```
108
+
109
+ If the avatar can't start (a wrong key, no minutes left), `avatar.failure` says why, with the API's `code`.
110
+
111
+ ## Changelog
112
+
113
+ - 0.1.0: first release. Tested with Pipecat v1.15.0 and daily-python 0.37.0.
114
+
115
+ ## License
116
+
117
+ BSD 2-Clause, like Pipecat.
@@ -0,0 +1,98 @@
1
+ # ChatFX Avatar for Pipecat
2
+
3
+ A real-time talking face for your Pipecat bot. Your bot's voice goes to the avatar, and its face and voice come back,
4
+ drawn together so the lips match, as your bot's own video and audio. You keep your own listening, AI and voice; ChatFX
5
+ adds the face, billed by the minute.
6
+
7
+ Tested with Pipecat v1.15.0.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pip install pipecat-chatfx
13
+ ```
14
+
15
+ Requires Python 3.10+ and `pipecat-ai` 1.8 or newer (it brings `pipecat-ai[daily]`).
16
+
17
+ ## Add your keys
18
+
19
+ - `CHATFX_AVATAR_API_KEY`: create one under **API keys** at [avatar.chatfx.com](https://avatar.chatfx.com).
20
+ - `DAILY_API_KEY`: from your [Daily dashboard](https://dashboard.daily.co/developers). Running on Pipecat Cloud, you already
21
+ have one. The avatar meets your bot in a private Daily room in your account, made for each call and removed when it
22
+ ends, the way Pipecat's own Tavus service works.
23
+
24
+ Put both in your bot's environment (your `.env`, or your Pipecat Cloud secret set).
25
+
26
+ ## Use it
27
+
28
+ Put `ChatFXVideoService` right after your TTS service, and turn on your transport's video out at the avatar's size:
29
+
30
+ ```python
31
+ from pipecat_chatfx import ChatFXVideoService
32
+
33
+ avatar = ChatFXVideoService(avatar_id="chatfx-lois") # copy the id from the Avatars page
34
+
35
+ pipeline = Pipeline([
36
+ transport.input(),
37
+ stt,
38
+ user_aggregator,
39
+ llm,
40
+ tts,
41
+ avatar,
42
+ transport.output(),
43
+ assistant_aggregator,
44
+ ])
45
+ ```
46
+
47
+ ```python
48
+ TransportParams( # or DailyParams
49
+ audio_in_enabled=True,
50
+ audio_out_enabled=True,
51
+ video_out_enabled=True,
52
+ video_out_is_live=True,
53
+ video_out_width=912, # 912 x 512 landscape, 512 x 512 square, 384 x 512 portrait
54
+ video_out_height=512,
55
+ video_out_framerate=25,
56
+ )
57
+ ```
58
+
59
+ That's all the code. When your pipeline ends (or is cancelled when the visitor leaves), the avatar's session ends too, so
60
+ billing stops. Your page shows the bot's video as before: the avatar is the bot.
61
+
62
+ Step by step: [Connecting your agent: Pipecat](https://chatfx.com/support/avatar-connect/#pipecat). A full sample bot
63
+ (Deepgram, OpenAI, Cartesia) comes in this package's source download, in `examples/`: `uv run bot.py`, then open
64
+ http://localhost:7860/client.
65
+
66
+ ## What it does for you
67
+
68
+ - **Shows a waiting picture.** Until the live face is in, your bot's video is the avatar's picture with "Video starting..."
69
+ on it.
70
+ - **Greets with the face.** Your bot's first words wait up to 10 seconds for the face, so they come with it.
71
+ - **Never depends on the face.** If the face can't come, or leaves mid-call, your bot carries on with its own voice.
72
+ - **Stops at once when talked over.** An interruption stops the avatar mid-word.
73
+ - **Lets the last words finish.** At the end of a call, the avatar finishes its goodbye before it leaves.
74
+
75
+ ## Options
76
+
77
+ ```python
78
+ ChatFXVideoService(
79
+ avatar_id="chatfx-lois",
80
+ api_key=None, # defaults to CHATFX_AVATAR_API_KEY
81
+ daily_api_key=None, # defaults to DAILY_API_KEY
82
+ api_url=None, # defaults to https://api.chatfx.com
83
+ face_first_seconds=10.0, # how long the first words wait for the face
84
+ start_timeout=120.0, # how long to keep trying to start the avatar
85
+ waiting_picture=True, # show the avatar's picture until the live face is in
86
+ waiting_text="Video starting...", # the words on it, in your language (None: no words)
87
+ )
88
+ ```
89
+
90
+ If the avatar can't start (a wrong key, no minutes left), `avatar.failure` says why, with the API's `code`.
91
+
92
+ ## Changelog
93
+
94
+ - 0.1.0: first release. Tested with Pipecat v1.15.0 and daily-python 0.37.0.
95
+
96
+ ## License
97
+
98
+ BSD 2-Clause, like Pipecat.
@@ -0,0 +1,14 @@
1
+ # Face (ChatFX Avatar): https://avatar.chatfx.com, under API keys
2
+ CHATFX_AVATAR_API_KEY=
3
+
4
+ # Where the avatar meets your bot: a private room in your Daily account. https://dashboard.daily.co/developers
5
+ DAILY_API_KEY=
6
+
7
+ # Speech to text (Deepgram): https://console.deepgram.com
8
+ DEEPGRAM_API_KEY=
9
+
10
+ # LLM (OpenAI): https://platform.openai.com/api-keys
11
+ OPENAI_API_KEY=
12
+
13
+ # Voice (Cartesia): https://play.cartesia.ai/keys
14
+ CARTESIA_API_KEY=
@@ -0,0 +1,4 @@
1
+ .env
2
+ .venv/
3
+ __pycache__/
4
+ *.pyc
@@ -0,0 +1,126 @@
1
+ """A Pipecat bot with a ChatFX Avatar face.
2
+
3
+ Speech to text: Deepgram. LLM: OpenAI. Voice: Cartesia. Face: ChatFX Avatar, right after the voice.
4
+
5
+ Put your keys in .env (see .env.example), then:
6
+
7
+ uv run bot.py
8
+
9
+ and open http://localhost:7860/client. Click Connect and allow the microphone: the avatar appears and says the first message.
10
+ """
11
+
12
+ import os
13
+
14
+ from dotenv import load_dotenv
15
+ from loguru import logger
16
+ from pipecat.audio.vad.silero import SileroVADAnalyzer
17
+ from pipecat.frames.frames import TTSSpeakFrame
18
+ from pipecat.pipeline.pipeline import Pipeline
19
+ from pipecat.pipeline.worker import PipelineParams, PipelineWorker
20
+ from pipecat.processors.aggregators.llm_context import LLMContext
21
+ from pipecat.processors.aggregators.llm_response_universal import LLMContextAggregatorPair, LLMUserAggregatorParams
22
+ from pipecat.runner.types import RunnerArguments
23
+ from pipecat.runner.utils import create_transport
24
+ from pipecat.services.cartesia.tts import CartesiaTTSService
25
+ from pipecat.services.deepgram.stt import DeepgramSTTService
26
+ from pipecat.services.openai.llm import OpenAILLMService
27
+ from pipecat.transports.base_transport import BaseTransport, TransportParams
28
+ from pipecat.transports.daily.transport import DailyParams
29
+ from pipecat.workers.runner import WorkerRunner
30
+
31
+ from pipecat_chatfx import ChatFXVideoService
32
+
33
+ load_dotenv(override=True)
34
+
35
+ SYSTEM_PROMPT = "You are a friendly assistant on a video call. Keep answers short, with no special characters, emojis or markdown: they are spoken."
36
+ FIRST_MESSAGE = "Hello! What can I help you with today?"
37
+ # Copy the id from the Avatars page at avatar.chatfx.com.
38
+ AVATAR_ID = "chatfx-lois"
39
+ # The avatar's size: 912 x 512 for a landscape avatar, 512 x 512 square, 384 x 512 portrait.
40
+ VIDEO_WIDTH = 912
41
+ VIDEO_HEIGHT = 512
42
+
43
+ # "webrtc" for testing on your machine, "daily" on Pipecat Cloud. The avatar sends 25 pictures a second.
44
+ transport_params = {
45
+ "daily": lambda: DailyParams(
46
+ audio_in_enabled=True,
47
+ audio_out_enabled=True,
48
+ video_out_enabled=True,
49
+ video_out_is_live=True,
50
+ video_out_width=VIDEO_WIDTH,
51
+ video_out_height=VIDEO_HEIGHT,
52
+ video_out_framerate=25,
53
+ ),
54
+ "webrtc": lambda: TransportParams(
55
+ audio_in_enabled=True,
56
+ audio_out_enabled=True,
57
+ video_out_enabled=True,
58
+ video_out_is_live=True,
59
+ video_out_width=VIDEO_WIDTH,
60
+ video_out_height=VIDEO_HEIGHT,
61
+ video_out_framerate=25,
62
+ ),
63
+ }
64
+
65
+
66
+ async def run_bot(transport: BaseTransport, runner_args: RunnerArguments):
67
+ stt = DeepgramSTTService(api_key=os.environ["DEEPGRAM_API_KEY"])
68
+ llm = OpenAILLMService(api_key=os.environ["OPENAI_API_KEY"], settings=OpenAILLMService.Settings(system_instruction=SYSTEM_PROMPT))
69
+ tts = CartesiaTTSService(
70
+ api_key=os.environ["CARTESIA_API_KEY"],
71
+ # Any Cartesia voice id.
72
+ settings=CartesiaTTSService.Settings(voice="71a7ad14-091c-4e8e-a314-022ece01c121"),
73
+ )
74
+ # CHATFX_AVATAR_API_KEY and DAILY_API_KEY come from .env.
75
+ avatar = ChatFXVideoService(avatar_id=AVATAR_ID)
76
+
77
+ context = LLMContext()
78
+ user_aggregator, assistant_aggregator = LLMContextAggregatorPair(
79
+ context,
80
+ user_params=LLMUserAggregatorParams(vad_analyzer=SileroVADAnalyzer()),
81
+ )
82
+
83
+ pipeline = Pipeline(
84
+ [
85
+ transport.input(),
86
+ stt,
87
+ user_aggregator,
88
+ llm,
89
+ tts,
90
+ avatar,
91
+ transport.output(),
92
+ assistant_aggregator,
93
+ ]
94
+ )
95
+
96
+ worker = PipelineWorker(
97
+ pipeline,
98
+ params=PipelineParams(enable_metrics=True),
99
+ idle_timeout_secs=runner_args.pipeline_idle_timeout_secs,
100
+ )
101
+
102
+ @transport.event_handler("on_client_connected")
103
+ async def on_client_connected(transport, client):
104
+ logger.info("Client connected")
105
+ await worker.queue_frames([TTSSpeakFrame(FIRST_MESSAGE)])
106
+
107
+ @transport.event_handler("on_client_disconnected")
108
+ async def on_client_disconnected(transport, client):
109
+ # Ends the avatar's session too, so billing stops.
110
+ await worker.cancel()
111
+
112
+ runner = WorkerRunner(handle_sigint=runner_args.handle_sigint)
113
+ await runner.add_workers(worker)
114
+ await runner.run()
115
+
116
+
117
+ async def bot(runner_args: RunnerArguments):
118
+ """Entry point for the local runner and for Pipecat Cloud."""
119
+ transport = await create_transport(runner_args, transport_params)
120
+ await run_bot(transport, runner_args)
121
+
122
+
123
+ if __name__ == "__main__":
124
+ from pipecat.runner.run import main
125
+
126
+ main()
@@ -0,0 +1,10 @@
1
+ [project]
2
+ name = "chatfx-avatar-pipecat-bot"
3
+ version = "0.1.0"
4
+ description = "A Pipecat bot with a ChatFX Avatar face"
5
+ requires-python = ">=3.11"
6
+ dependencies = [
7
+ "pipecat-ai[daily,deepgram,cartesia,openai,runner,silero,webrtc]==1.15.0",
8
+ "pipecat-chatfx==0.1.0",
9
+ "python-dotenv>=1.0",
10
+ ]
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "pipecat-chatfx"
7
+ dynamic = ["version"]
8
+ description = "ChatFX Avatar for Pipecat: a real-time talking face for your Pipecat bot"
9
+ readme = "README.md"
10
+ license = "BSD-2-Clause"
11
+ license-files = ["LICENSE"]
12
+ requires-python = ">=3.10"
13
+ authors = [{ name = "ChatRep, Inc.", email = "service@chatfx.com" }]
14
+ keywords = ["pipecat", "avatar", "video", "voice", "realtime", "chatfx", "daily"]
15
+ classifiers = [
16
+ "Intended Audience :: Developers",
17
+ "Programming Language :: Python :: 3",
18
+ "Topic :: Multimedia :: Video",
19
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
20
+ ]
21
+ dependencies = ["pipecat-ai[daily]>=1.8", "aiohttp>=3.9"]
22
+
23
+ [project.urls]
24
+ Homepage = "https://chatfx.com/avatar/"
25
+ Documentation = "https://chatfx.com/support/avatar-connect/"
26
+
27
+ [tool.hatch.version]
28
+ path = "src/pipecat_chatfx/version.py"
29
+
30
+ [tool.hatch.build.targets.wheel]
31
+ packages = ["src/pipecat_chatfx"]
32
+
33
+ [tool.pytest.ini_options]
34
+ asyncio_mode = "auto"
35
+ asyncio_default_fixture_loop_scope = "function"
36
+ pythonpath = ["src"]
@@ -0,0 +1,6 @@
1
+ """ChatFX Avatar for Pipecat: a real-time talking face for your Pipecat bot. See ChatFXVideoService."""
2
+
3
+ from .version import __version__
4
+ from .video import ChatFXException, ChatFXVideoService
5
+
6
+ __all__ = ["ChatFXVideoService", "ChatFXException", "__version__"]
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"