Compare commits
448 Commits
aleix/no-n
...
v0.0.54
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd5075ed7a | ||
|
|
6f41a667c8 | ||
|
|
0b222a7eae | ||
|
|
f09f4b8fc4 | ||
|
|
cca241a2b7 | ||
|
|
1489e44740 | ||
|
|
f55f78e70e | ||
|
|
10202dc529 | ||
|
|
498805a34c | ||
|
|
509f143e1b | ||
|
|
737e4fa3bd | ||
|
|
8b5228a105 | ||
|
|
6cc01bc5b0 | ||
|
|
2a2928d96c | ||
|
|
a3a6adbd17 | ||
|
|
bf5ced18b2 | ||
|
|
2eccd1b1e9 | ||
|
|
9374bed878 | ||
|
|
c03d0352b1 | ||
|
|
af90b8b4fa | ||
|
|
0a9daa2f56 | ||
|
|
e48c0e52ef | ||
|
|
6bca8396d3 | ||
|
|
c2d8a45a07 | ||
|
|
80a7f1b1e7 | ||
|
|
aff6e24560 | ||
|
|
cb93f6b368 | ||
|
|
ff0bcec33a | ||
|
|
5885fcc230 | ||
|
|
57b186cde8 | ||
|
|
d1a3f404a5 | ||
|
|
179ddbea7d | ||
|
|
86c1e6a3bd | ||
|
|
9e9822f17d | ||
|
|
5f9671e2ca | ||
|
|
aac8961ae5 | ||
|
|
3e6377346a | ||
|
|
9d9a622b1a | ||
|
|
3e9a6b6262 | ||
|
|
fb3097560f | ||
|
|
ff6368add0 | ||
|
|
89fd03d86f | ||
|
|
0672530d6b | ||
|
|
7a0cfc8d3d | ||
|
|
b881dd57b3 | ||
|
|
abf0d0d053 | ||
|
|
1acdf7aff7 | ||
|
|
96b90abda6 | ||
|
|
202a844eeb | ||
|
|
655d56f634 | ||
|
|
07c84b733b | ||
|
|
7c52736ff6 | ||
|
|
48ce751602 | ||
|
|
1f1e2dac2b | ||
|
|
71c2dc3d05 | ||
|
|
ef02ece662 | ||
|
|
d5818fad5b | ||
|
|
dbea86baae | ||
|
|
c5faac1cf8 | ||
|
|
e106d7a215 | ||
|
|
40c1a8369a | ||
|
|
6ab2404a98 | ||
|
|
e61c996a2e | ||
|
|
2c81dc1f06 | ||
|
|
53251dcb88 | ||
|
|
d4e4b12109 | ||
|
|
466d26a4f2 | ||
|
|
ef511d580d | ||
|
|
5957ddb038 | ||
|
|
799c2d14b8 | ||
|
|
dee1224530 | ||
|
|
fc6aa6eae8 | ||
|
|
ddd5bf70ab | ||
|
|
aa59744444 | ||
|
|
067ddfe505 | ||
|
|
a64df978e7 | ||
|
|
7167719761 | ||
|
|
e1430be9f9 | ||
|
|
c2fe8e7fdb | ||
|
|
31c77d8e35 | ||
|
|
2a60d54830 | ||
|
|
b3c99887dc | ||
|
|
38ad75cc17 | ||
|
|
2debac314c | ||
|
|
e0c9a1a1a2 | ||
|
|
4cdcca588e | ||
|
|
a90e81e2eb | ||
|
|
0ba60c9e28 | ||
|
|
5ca5fbd825 | ||
|
|
2b52e2c109 | ||
|
|
7e8fc2e7e2 | ||
|
|
0d79a9eaa6 | ||
|
|
f89b9ec23f | ||
|
|
20d5824e56 | ||
|
|
f23baa78d8 | ||
|
|
cacd6ba3fa | ||
|
|
f87ecd3a51 | ||
|
|
b96a922aa8 | ||
|
|
401d3ff267 | ||
|
|
ab4221a4db | ||
|
|
bd6f82cf94 | ||
|
|
dd21b424d6 | ||
|
|
76884877dd | ||
|
|
0d6c680133 | ||
|
|
a27fe4bde2 | ||
|
|
177cb2ca8b | ||
|
|
3c970a3cee | ||
|
|
af02f8f1cd | ||
|
|
2e0fb198bf | ||
|
|
4f758c5a3b | ||
|
|
3e0836b340 | ||
|
|
2f23693bf3 | ||
|
|
b7dd9748cf | ||
|
|
d4d9c3b7ae | ||
|
|
090bc81ec5 | ||
|
|
9b61633aa0 | ||
|
|
e3d53d3d9a | ||
|
|
262d3a19c9 | ||
|
|
491feb691c | ||
|
|
e4f83b237e | ||
|
|
a169e0cde9 | ||
|
|
c6d643d4ec | ||
|
|
2abbd4bb27 | ||
|
|
e0011a3996 | ||
|
|
ea44c59ddd | ||
|
|
a9c7dbbc05 | ||
|
|
8a87e92b2b | ||
|
|
982f2becc6 | ||
|
|
e049ae470d | ||
|
|
e159f2dce1 | ||
|
|
e9162ae467 | ||
|
|
bb65512ff4 | ||
|
|
b81323d676 | ||
|
|
65fa77dfa5 | ||
|
|
9ddd9ae27c | ||
|
|
12fc6e17ef | ||
|
|
3e4020cdba | ||
|
|
4f883ee31f | ||
|
|
3ff360f042 | ||
|
|
45cbad5b3e | ||
|
|
477d0d154b | ||
|
|
4b3c776f58 | ||
|
|
da0c4cfd99 | ||
|
|
f22a00570d | ||
|
|
85f4663a41 | ||
|
|
915e3bb3c7 | ||
|
|
80779c48d6 | ||
|
|
c444557965 | ||
|
|
d51893f61c | ||
|
|
740d2743df | ||
|
|
0dd22fb879 | ||
|
|
225b65c3d2 | ||
|
|
2503f76107 | ||
|
|
ff8aa68942 | ||
|
|
c5edbf4b75 | ||
|
|
799777774b | ||
|
|
fdef8a97e2 | ||
|
|
0163247410 | ||
|
|
221e044046 | ||
|
|
532fd31fd7 | ||
|
|
3e178fd46f | ||
|
|
07cb8b7a89 | ||
|
|
e805738d4c | ||
|
|
119bc7e35f | ||
|
|
b9b02845a3 | ||
|
|
3714f12edc | ||
|
|
d2b8171197 | ||
|
|
d0b48c95bb | ||
|
|
73ed0c1ad7 | ||
|
|
c211580fec | ||
|
|
359b55a85e | ||
|
|
8b602a3f62 | ||
|
|
485c231f69 | ||
|
|
8ba3b150eb | ||
|
|
b5f72b4378 | ||
|
|
85e7d62f94 | ||
|
|
923d33eeff | ||
|
|
7ee6e7193d | ||
|
|
156fffe6fc | ||
|
|
c9834e2712 | ||
|
|
1e7e307f69 | ||
|
|
67e47a388d | ||
|
|
dcf317f2fa | ||
|
|
b8ffd7b16b | ||
|
|
08f1dda94e | ||
|
|
45039e7cde | ||
|
|
e50c76d075 | ||
|
|
dd9f9179cc | ||
|
|
c8da531402 | ||
|
|
25bcaf5c7c | ||
|
|
2d0f3341c3 | ||
|
|
7626d7b04b | ||
|
|
f78520f7d0 | ||
|
|
bb4766455d | ||
|
|
9dacbbbbf4 | ||
|
|
4de192fbb0 | ||
|
|
80b6c28431 | ||
|
|
f471744bca | ||
|
|
d5df4b064b | ||
|
|
06a0e29920 | ||
|
|
64eb8e7262 | ||
|
|
d8386c12dc | ||
|
|
50e798bcd9 | ||
|
|
d1ac7751da | ||
|
|
110ce27c91 | ||
|
|
8b657158ca | ||
|
|
cce14fca97 | ||
|
|
7c051516d8 | ||
|
|
5f402ad741 | ||
|
|
a80b186cea | ||
|
|
c65aaf3b2e | ||
|
|
e815d7776f | ||
|
|
11fc08ef24 | ||
|
|
6f3b0fdf73 | ||
|
|
885bc32827 | ||
|
|
7339cc7197 | ||
|
|
62e9e6bc5a | ||
|
|
329da50338 | ||
|
|
4d307d26d8 | ||
|
|
a74b9354ec | ||
|
|
11381a536f | ||
|
|
b53bc8a879 | ||
|
|
e3d8910814 | ||
|
|
e60a59434f | ||
|
|
5e5de618f3 | ||
|
|
8af92f7923 | ||
|
|
f39e17857e | ||
|
|
5b632de04a | ||
|
|
6bcc196489 | ||
|
|
66375e9dff | ||
|
|
bc839492b6 | ||
|
|
4854645637 | ||
|
|
98e80b7d4a | ||
|
|
8c0ecb89de | ||
|
|
4c8fcb2cfc | ||
|
|
92313d6ce7 | ||
|
|
1ca6ecc46e | ||
|
|
f1947d7d38 | ||
|
|
0852570212 | ||
|
|
874b8bb136 | ||
|
|
da1878537b | ||
|
|
f406d93b0f | ||
|
|
3cd2b90177 | ||
|
|
c4f0c7bcfd | ||
|
|
95e69597f3 | ||
|
|
710baa5e17 | ||
|
|
14e5419913 | ||
|
|
8c953bac41 | ||
|
|
4c0861ce39 | ||
|
|
12b1e1db9d | ||
|
|
53bfdfd83f | ||
|
|
2a5593afea | ||
|
|
a04a920e54 | ||
|
|
2ce6d92455 | ||
|
|
1ecd5da219 | ||
|
|
e04da334d7 | ||
|
|
7ec351813c | ||
|
|
df6c2fc403 | ||
|
|
71e107725c | ||
|
|
4d0c11fcab | ||
|
|
a8ae79831e | ||
|
|
86516d2415 | ||
|
|
5cd9dab14b | ||
|
|
a3e2e06975 | ||
|
|
e7107b99c5 | ||
|
|
aa1b8879ee | ||
|
|
6802459165 | ||
|
|
6719d1fddc | ||
|
|
a798bf18f2 | ||
|
|
f9d0cca60f | ||
|
|
cb22de0d13 | ||
|
|
7d161cc53b | ||
|
|
255abf46ef | ||
|
|
27579bcb70 | ||
|
|
1295b64879 | ||
|
|
ca57670f65 | ||
|
|
06d0a231b9 | ||
|
|
67af4e619b | ||
|
|
21c274944e | ||
|
|
3239249feb | ||
|
|
216979c377 | ||
|
|
b9db53d3cd | ||
|
|
58bfcc8370 | ||
|
|
6664c492ac | ||
|
|
7634058f97 | ||
|
|
39c6446bdc | ||
|
|
2df7dfcc91 | ||
|
|
c23c9e046c | ||
|
|
9dae753e8c | ||
|
|
40e9ee6d63 | ||
|
|
a342fe732e | ||
|
|
a729834482 | ||
|
|
94a6f1086e | ||
|
|
b42d3a8257 | ||
|
|
12ae980abe | ||
|
|
cdb909958c | ||
|
|
c72c3025f6 | ||
|
|
5cbd719780 | ||
|
|
23d6290672 | ||
|
|
d4e7e11981 | ||
|
|
8057fe3fcf | ||
|
|
3b446234a7 | ||
|
|
768487ffb3 | ||
|
|
2da5620d10 | ||
|
|
af90d65b3b | ||
|
|
c8569a7b67 | ||
|
|
0ecd98c873 | ||
|
|
6f863ba2c6 | ||
|
|
602ca5ebe6 | ||
|
|
787ade41f3 | ||
|
|
bb767831d5 | ||
|
|
bc25a771dc | ||
|
|
f37626f81d | ||
|
|
9d54578e65 | ||
|
|
79afe7ec2a | ||
|
|
2c1fd3c3cc | ||
|
|
b0dd8e03a6 | ||
|
|
ee20e48ef8 | ||
|
|
12b5c5a646 | ||
|
|
7a021cc82d | ||
|
|
3e1ec4a8ee | ||
|
|
a1377b7f1a | ||
|
|
d6335886e2 | ||
|
|
b3b7a5f023 | ||
|
|
5138017b57 | ||
|
|
87670067d7 | ||
|
|
656cd2859e | ||
|
|
15b2cc210c | ||
|
|
4667624b60 | ||
|
|
d07ba80572 | ||
|
|
386ba61483 | ||
|
|
e9d275f270 | ||
|
|
3a4994370c | ||
|
|
6125ea882d | ||
|
|
0a1ce1bb63 | ||
|
|
ab3bcde5f7 | ||
|
|
1368d3db5c | ||
|
|
cd7dec7391 | ||
|
|
a5e985094b | ||
|
|
c04c69df95 | ||
|
|
9c105e25ac | ||
|
|
6901c4fa57 | ||
|
|
469c13c07e | ||
|
|
46871ae686 | ||
|
|
ab5df1a236 | ||
|
|
f5f0de00e4 | ||
|
|
f3dd35bfd9 | ||
|
|
53a5e63990 | ||
|
|
d435a6a6d6 | ||
|
|
59240c7b96 | ||
|
|
6c11753985 | ||
|
|
6fabb7e7d5 | ||
|
|
bce218915e | ||
|
|
627c91f4a6 | ||
|
|
dac4468ca1 | ||
|
|
503eddf7d6 | ||
|
|
1a0f6f2a21 | ||
|
|
43759295cc | ||
|
|
900b95eb92 | ||
|
|
41d07692ca | ||
|
|
dcf6b6e120 | ||
|
|
99dba3b6b9 | ||
|
|
4547609ffb | ||
|
|
9554804a49 | ||
|
|
656cbc35e1 | ||
|
|
6f7c4dd998 | ||
|
|
8b496f8c6f | ||
|
|
15047f5f0a | ||
|
|
e08c24dc41 | ||
|
|
5341739ece | ||
|
|
5b0fc3fa15 | ||
|
|
b7b8e59e9e | ||
|
|
6e0d3aef32 | ||
|
|
1ccc84dd7a | ||
|
|
c9dd906057 | ||
|
|
4f093f11db | ||
|
|
887a9170b2 | ||
|
|
f2e191855a | ||
|
|
78b90e9591 | ||
|
|
17decee788 | ||
|
|
f89014d100 | ||
|
|
3b3e22fe7c | ||
|
|
0df0194cc1 | ||
|
|
8a7a61914e | ||
|
|
1117c21483 | ||
|
|
4211664a77 | ||
|
|
1f8a217cd1 | ||
|
|
b5bd662fe1 | ||
|
|
dd2703317a | ||
|
|
77aeda36eb | ||
|
|
51b235df4b | ||
|
|
4f2aee5fba | ||
|
|
55879bf365 | ||
|
|
7322badbe7 | ||
|
|
42bea578e8 | ||
|
|
2dfdceb9e6 | ||
|
|
5bfcac1f5c | ||
|
|
fb9f72d38b | ||
|
|
146a341a38 | ||
|
|
b9ca667d31 | ||
|
|
5c57cccea3 | ||
|
|
17162258a2 | ||
|
|
da3fb98101 | ||
|
|
6244124d14 | ||
|
|
53049adeea | ||
|
|
4208d2d7c4 | ||
|
|
9f7f74e4d8 | ||
|
|
f14d32d09e | ||
|
|
7351e281e2 | ||
|
|
b94b10f7d6 | ||
|
|
1cc90eb1a3 | ||
|
|
5f7d28bb05 | ||
|
|
204a08ab8f | ||
|
|
141b0a6560 | ||
|
|
ca086a856f | ||
|
|
fe0a7d07bd | ||
|
|
79eb29d614 | ||
|
|
da15c83bab | ||
|
|
d6bac77b3c | ||
|
|
7faa4eb295 | ||
|
|
0e31413851 | ||
|
|
16948b251d | ||
|
|
f3112a8638 | ||
|
|
0293d40e4e | ||
|
|
64038442ed | ||
|
|
facc280599 | ||
|
|
f90cbe8086 | ||
|
|
09a611d44b | ||
|
|
16d7fb2c4a | ||
|
|
643160c960 | ||
|
|
aac907aadb | ||
|
|
8f24ca4e58 | ||
|
|
420ce16807 | ||
|
|
2b8c35c681 | ||
|
|
3d96369193 | ||
|
|
d44b36a07c | ||
|
|
ccc96994e9 | ||
|
|
337d421338 | ||
|
|
752720b4d5 | ||
|
|
f8e69cfa00 | ||
|
|
6d11911d83 | ||
|
|
ec6e71c8ea | ||
|
|
62fc95300b | ||
|
|
6e8e7fa19a | ||
|
|
7dfa886669 | ||
|
|
da254c5143 | ||
|
|
e11f128110 | ||
|
|
3aa89fb13a |
48
.github/workflows/android.yaml
vendored
Normal file
48
.github/workflows/android.yaml
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
name: android
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
paths:
|
||||||
|
- "examples/simple-chatbot/client/android/**"
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- "**"
|
||||||
|
paths:
|
||||||
|
- "examples/simple-chatbot/client/android/**"
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
sdk_git_ref:
|
||||||
|
type: string
|
||||||
|
description: "Which git ref of the app to build"
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: build-android-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
sdk:
|
||||||
|
name: "Simple chatbot demo"
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.inputs.sdk_git_ref || github.ref }}
|
||||||
|
|
||||||
|
- name: "Install Java"
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: 'temurin'
|
||||||
|
java-version: '17'
|
||||||
|
|
||||||
|
- name: Build demo app
|
||||||
|
working-directory: examples/simple-chatbot/client/android
|
||||||
|
run: ./gradlew :simple-chatbot-client:assembleDebug
|
||||||
|
|
||||||
|
- name: Upload demo APK
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: Simple Chatbot Android Client
|
||||||
|
path: examples/simple-chatbot/client/android/simple-chatbot-client/build/outputs/apk/debug/simple-chatbot-client-debug.apk
|
||||||
7
.github/workflows/format.yaml
vendored
7
.github/workflows/format.yaml
vendored
@@ -35,7 +35,12 @@ jobs:
|
|||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
pip install -r dev-requirements.txt
|
pip install -r dev-requirements.txt
|
||||||
- name: Ruff formatter
|
- name: Ruff formatter
|
||||||
id: ruff
|
id: ruff-format
|
||||||
run: |
|
run: |
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
ruff format --diff
|
ruff format --diff
|
||||||
|
- name: Ruff import linter
|
||||||
|
id: ruff-check
|
||||||
|
run: |
|
||||||
|
source .venv/bin/activate
|
||||||
|
ruff check --select I
|
||||||
|
|||||||
4
.github/workflows/tests.yaml
vendored
4
.github/workflows/tests.yaml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: test
|
name: tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
@@ -49,4 +49,4 @@ jobs:
|
|||||||
- name: Test with pytest
|
- name: Test with pytest
|
||||||
run: |
|
run: |
|
||||||
source .venv/bin/activate
|
source .venv/bin/activate
|
||||||
pytest --ignore-glob="*to_be_updated*" --ignore-glob=*pipeline_source* src tests
|
pytest
|
||||||
|
|||||||
7
.pre-commit-config.yaml
Normal file
7
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
repos:
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: ruff-format-hook
|
||||||
|
name: Check ruff formatting
|
||||||
|
entry: sh scripts/pre-commit.sh
|
||||||
|
language: system
|
||||||
275
CHANGELOG.md
275
CHANGELOG.md
@@ -5,23 +5,263 @@ All notable changes to **Pipecat** will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [Unreleased]
|
## [0.0.54] - 2025-01-27
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- In order to create tasks in Pipecat frame processors it is now recommended to
|
||||||
|
use `FrameProcessor.create_task()` (which uses the new
|
||||||
|
`utils.asyncio.create_task()`). It takes care of uncaught exceptions, task
|
||||||
|
cancellation handling and task management. To cancel or wait for a task there
|
||||||
|
is `FrameProcessor.cancel_task()` and `FrameProcessor.wait_for_task()`. All of
|
||||||
|
Pipecat processors have been updated accordingly. Also, when a pipeline runner
|
||||||
|
finishes, a warning about dangling tasks might appear, which indicates if any
|
||||||
|
of the created tasks was never cancelled or awaited for (using these new
|
||||||
|
functions).
|
||||||
|
|
||||||
|
- It is now possible to specify the period of the `PipelineTask` heartbeat
|
||||||
|
frames with `heartbeats_period_secs`.
|
||||||
|
|
||||||
|
- Added `DailyMeetingTokenProperties` and `DailyMeetingTokenParams` Pydantic models
|
||||||
|
for meeting token creation in `get_token` method of `DailyRESTHelper`.
|
||||||
|
|
||||||
|
- Added `enable_recording` and `geo` parameters to `DailyRoomProperties`.
|
||||||
|
|
||||||
|
- Added `RecordingsBucketConfig` to `DailyRoomProperties` to upload recordings to a custom AWS bucket.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Enhanced `UserIdleProcessor` with retry functionality and control over idle
|
||||||
|
monitoring via new callback signature `(processor, retry_count) -> bool`.
|
||||||
|
Updated the `17-detect-user-idle.py` to show how to use the `retry_count`.
|
||||||
|
|
||||||
|
- Add defensive error handling for `OpenAIRealtimeBetaLLMService`'s audio
|
||||||
|
truncation. Audio truncation errors during interruptions now log a warning
|
||||||
|
and allow the session to continue instead of throwing an exception.
|
||||||
|
|
||||||
|
- Modified `TranscriptProcessor` to use TTS text frames for more accurate assistant
|
||||||
|
transcripts. Assistant messages are now aggregated based on bot speaking boundaries
|
||||||
|
rather than LLM context, providing better handling of interruptions and partial
|
||||||
|
utterances.
|
||||||
|
|
||||||
|
- Updated foundational examples `28a-transcription-processor-openai.py`,
|
||||||
|
`28b-transcript-processor-anthropic.py`, and
|
||||||
|
`28c-transcription-processor-gemini.py` to use the updated
|
||||||
|
`TranscriptProcessor`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed an `GeminiMultimodalLiveLLMService` issue that was preventing the user
|
||||||
|
to push initial LLM assistant messages (using `LLMMessagesAppendFrame`).
|
||||||
|
|
||||||
|
- Added missing `FrameProcessor.cleanup()` calls to `Pipeline`,
|
||||||
|
`ParallelPipeline` and `UserIdleProcessor`.
|
||||||
|
|
||||||
|
- Fixed a type error when using `voice_settings` in `ElevenLabsHttpTTSService`.
|
||||||
|
|
||||||
|
- Fixed an issue where `OpenAIRealtimeBetaLLMService` function calling resulted
|
||||||
|
in an error.
|
||||||
|
|
||||||
|
- Fixed an issue in `AudioBufferProcessor` where the last audio buffer was not
|
||||||
|
being processed, in cases where the `_user_audio_buffer` was smaller than the
|
||||||
|
buffer size.
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
|
||||||
|
- Replaced audio resampling library `resampy` with `soxr`. Resampling a 2:21s
|
||||||
|
audio file from 24KHz to 16KHz took 1.41s with `resampy` and 0.031s with
|
||||||
|
`soxr` with similar audio quality.
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- Added initial unit test infrastructure.
|
||||||
|
|
||||||
|
## [0.0.53] - 2025-01-18
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `ElevenLabsHttpTTSService` which uses EleveLabs' HTTP API instead of the
|
||||||
|
websocket one.
|
||||||
|
|
||||||
|
- Introduced pipeline frame observers. Observers can view all the frames that go
|
||||||
|
through the pipeline without the need to inject processors in the
|
||||||
|
pipeline. This can be useful, for example, to implement frame loggers or
|
||||||
|
debuggers among other things. The example
|
||||||
|
`examples/foundational/30-observer.py` shows how to add an observer to a
|
||||||
|
pipeline for debugging.
|
||||||
|
|
||||||
|
- Introduced heartbeat frames. The pipeline task can now push periodic
|
||||||
|
heartbeats down the pipeline when `enable_heartbeats=True`. Heartbeats are
|
||||||
|
system frames that are supposed to make it all the way to the end of the
|
||||||
|
pipeline. When a heartbeat frame is received the traversing time (i.e. the
|
||||||
|
time it took to go through the whole pipeline) will be displayed (with TRACE
|
||||||
|
logging) otherwise a warning will be shown. The example
|
||||||
|
`examples/foundational/31-heartbeats.py` shows how to enable heartbeats and
|
||||||
|
forces warnings to be displayed.
|
||||||
|
|
||||||
|
- Added `LLMTextFrame` and `TTSTextFrame` which should be pushed by LLM and TTS
|
||||||
|
services respectively instead of `TextFrame`s.
|
||||||
|
|
||||||
|
- Added `OpenRouter` for OpenRouter integration with an OpenAI-compatible
|
||||||
|
interface. Added foundational example `14m-function-calling-openrouter.py`.
|
||||||
|
|
||||||
|
- Added a new `WebsocketService` based class for TTS services, containing
|
||||||
|
base functions and retry logic.
|
||||||
|
|
||||||
|
- Added `DeepSeekLLMService` for DeepSeek integration with an OpenAI-compatible
|
||||||
|
interface. Added foundational example `14l-function-calling-deepseek.py`.
|
||||||
|
|
||||||
|
- Added `FunctionCallResultProperties` dataclass to provide a structured way to
|
||||||
|
control function call behavior, including:
|
||||||
|
|
||||||
|
- `run_llm`: Controls whether to trigger LLM completion
|
||||||
|
- `on_context_updated`: Optional callback triggered after context update
|
||||||
|
|
||||||
|
- Added a new foundational example `07e-interruptible-playht-http.py` for easy
|
||||||
|
testing of `PlayHTHttpTTSService`.
|
||||||
|
|
||||||
|
- Added support for Google TTS Journey voices in `GoogleTTSService`.
|
||||||
|
|
||||||
|
- Added `29-livekit-audio-chat.py`, as a new foundational examples for
|
||||||
|
`LiveKitTransportLayer`.
|
||||||
|
|
||||||
|
- Added `enable_prejoin_ui`, `max_participants` and `start_video_off` params
|
||||||
|
to `DailyRoomProperties`.
|
||||||
|
|
||||||
|
- Added `session_timeout` to `FastAPIWebsocketTransport` and
|
||||||
|
`WebsocketServerTransport` for configuring session timeouts (in
|
||||||
|
seconds). Triggers `on_session_timeout` for custom timeout handling.
|
||||||
|
See [examples/websocket-server/bot.py](https://github.com/pipecat-ai/pipecat/blob/main/examples/websocket-server/bot.py).
|
||||||
|
|
||||||
|
- Added the new modalities option and helper function to set Gemini output
|
||||||
|
modalities.
|
||||||
|
|
||||||
|
- Added `examples/foundational/26d-gemini-multimodal-live-text.py` which is
|
||||||
|
using Gemini as TEXT modality and using another TTS provider for TTS process.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Modified `UserIdleProcessor` to start monitoring only after first
|
||||||
|
conversation activity (`UserStartedSpeakingFrame` or
|
||||||
|
`BotStartedSpeakingFrame`) instead of immediately.
|
||||||
|
|
||||||
|
- Modified `OpenAIAssistantContextAggregator` to support controlled completions
|
||||||
|
and to emit context update callbacks via `FunctionCallResultProperties`.
|
||||||
|
|
||||||
|
- Added `aws_session_token` to the `PollyTTSService`.
|
||||||
|
|
||||||
|
- Changed the default model for `PlayHTHttpTTSService` to `Play3.0-mini-http`.
|
||||||
|
|
||||||
|
- `api_key`, `aws_access_key_id` and `region` are no longer required parameters
|
||||||
|
for the PollyTTSService (AWSTTSService)
|
||||||
|
|
||||||
|
- Added `session_timeout` example in `examples/websocket-server/bot.py` to
|
||||||
|
handle session timeout event.
|
||||||
|
|
||||||
|
- Changed `InputParams` in
|
||||||
|
`src/pipecat/services/gemini_multimodal_live/gemini.py` to support different
|
||||||
|
modalities.
|
||||||
|
|
||||||
|
- Changed `DeepgramSTTService` to send `finalize` event whenever VAD detects
|
||||||
|
`UserStoppedSpeakingFrame`. This helps in faster transcriptions and clearing
|
||||||
|
the `Deepgram` audio buffer.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed an issue where `DeepgramSTTService` was not generating metrics using
|
||||||
|
pipeline's VAD.
|
||||||
|
|
||||||
|
- Fixed `UserIdleProcessor` not properly propagating `EndFrame`s through the
|
||||||
|
pipeline.
|
||||||
|
|
||||||
|
- Fixed an issue where websocket based TTS services could incorrectly terminate
|
||||||
|
their connection due to a retry counter not resetting.
|
||||||
|
|
||||||
|
- Fixed a `PipelineTask` issue that would cause a dangling task after stopping
|
||||||
|
the pipeline with an `EndFrame`.
|
||||||
|
|
||||||
|
- Fixed an import issue for `PlayHTHttpTTSService`.
|
||||||
|
|
||||||
|
- Fixed an issue where languages couldn't be used with the `PlayHTHttpTTSService`.
|
||||||
|
|
||||||
|
- Fixed an issue where `OpenAIRealtimeBetaLLMService` audio chunks were hitting
|
||||||
|
an error when truncating audio content.
|
||||||
|
|
||||||
|
- Fixed an issue where setting the voice and model for `RimeHttpTTSService`
|
||||||
|
wasn't working.
|
||||||
|
|
||||||
|
- Fixed an issue where `IdleFrameProcessor` and `UserIdleProcessor` were getting
|
||||||
|
initialized before the start of the pipeline.
|
||||||
|
|
||||||
|
## [0.0.52] - 2024-12-24
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Constructor arguments for GoogleLLMService to directly set tools and tool_config.
|
||||||
|
|
||||||
|
- Smart turn detection example (`22d-natural-conversation-gemini-audio.py`) that
|
||||||
|
leverages Gemini 2.0 capabilities ().
|
||||||
|
(see https://x.com/kwindla/status/1870974144831275410)
|
||||||
|
|
||||||
|
- Added `DailyTransport.send_dtmf()` to send dial-out DTMF tones.
|
||||||
|
|
||||||
|
- Added `DailyTransport.sip_call_transfer()` to forward SIP and PSTN calls to
|
||||||
|
another address or number. For example, transfer a SIP call to a different
|
||||||
|
SIP address or transfer a PSTN phone number to a different PSTN phone number.
|
||||||
|
|
||||||
|
- Added `DailyTransport.sip_refer()` to transfer incoming SIP/PSTN calls from
|
||||||
|
outside Daily to another SIP/PSTN address.
|
||||||
|
|
||||||
|
- Added an `auto_mode` input parameter to `ElevenLabsTTSService`. `auto_mode`
|
||||||
|
is set to `True` by default. Enabling this setting disables the chunk
|
||||||
|
schedule and all buffers, which reduces latency.
|
||||||
|
|
||||||
|
- Added `KoalaFilter` which implement on device noise reduction using Koala
|
||||||
|
Noise Suppression.
|
||||||
|
(see https://picovoice.ai/platform/koala/)
|
||||||
|
|
||||||
|
- Added `CerebrasLLMService` for Cerebras integration with an OpenAI-compatible
|
||||||
|
interface. Added foundational example `14k-function-calling-cerebras.py`.
|
||||||
|
|
||||||
|
- Pipecat now supports Python 3.13. We had a dependency on the `audioop` package
|
||||||
|
which was deprecated and now removed on Python 3.13. We are now using
|
||||||
|
`audioop-lts` (https://github.com/AbstractUmbra/audioop) to provide the same
|
||||||
|
functionality.
|
||||||
|
|
||||||
|
- Added timestamped conversation transcript support:
|
||||||
|
|
||||||
|
- New `TranscriptProcessor` factory provides access to user and assistant
|
||||||
|
transcript processors.
|
||||||
|
- `UserTranscriptProcessor` processes user speech with timestamps from
|
||||||
|
transcription.
|
||||||
|
- `AssistantTranscriptProcessor` processes assistant responses with LLM
|
||||||
|
context timestamps.
|
||||||
|
- Messages emitted with ISO 8601 timestamps indicating when they were spoken.
|
||||||
|
- Supports all LLM formats (OpenAI, Anthropic, Google) via standard message
|
||||||
|
format.
|
||||||
|
- New examples: `28a-transcription-processor-openai.py`,
|
||||||
|
`28b-transcription-processor-anthropic.py`, and
|
||||||
|
`28c-transcription-processor-gemini.py`.
|
||||||
|
|
||||||
- Add support for more languages to ElevenLabs (Arabic, Croatian, Filipino,
|
- Add support for more languages to ElevenLabs (Arabic, Croatian, Filipino,
|
||||||
Tamil) and PlayHT (Afrikans, Albanian, Amharic, Arabic, Bengali, Croatian,
|
Tamil) and PlayHT (Afrikans, Albanian, Amharic, Arabic, Bengali, Croatian,
|
||||||
Galician, Hebrew, Mandarin, Serbian, Tagalog, Urdu, Xhosa).
|
Galician, Hebrew, Mandarin, Serbian, Tagalog, Urdu, Xhosa).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- It's no longer necessary to call `super().start/stop/cancel(frame)` if you
|
- `PlayHTTTSService` uses the new v4 websocket API, which also fixes an issue
|
||||||
subclass and implement `AIService.start/stop/cancel()`. This is all now done
|
where text inputted to the TTS didn't return audio.
|
||||||
internally and will avoid possible issues if you forget to add it.
|
|
||||||
|
|
||||||
- It's no longer necessary to call `super().process_frame(frame, direction)` if
|
- The default model for `ElevenLabsTTSService` is now `eleven_flash_v2_5`.
|
||||||
you subclass and implement `FrameProcessor.process_frame()`. This is all now
|
|
||||||
done internally and will avoid possible issues if you forget to add it.
|
- `OpenAIRealtimeBetaLLMService` now takes a `model` parameter in the
|
||||||
|
constructor.
|
||||||
|
|
||||||
|
- Updated the default model for the `OpenAIRealtimeBetaLLMService`.
|
||||||
|
|
||||||
|
- Room expiration (`exp`) in `DailyRoomProperties` is now optional (`None`) by
|
||||||
|
default instead of automatically setting a 5-minute expiration time. You must
|
||||||
|
explicitly set expiration time if desired.
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
||||||
@@ -29,12 +269,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed token counting in `GoogleLLMService`. Tokens were summed incorrectly
|
||||||
|
(double-counted in many cases).
|
||||||
|
|
||||||
|
- Fixed an issue that could cause the bot to stop talking if there was a user
|
||||||
|
interruption before getting any audio from the TTS service.
|
||||||
|
|
||||||
|
- Fixed an issue that would cause `ParallelPipeline` to handle `EndFrame`
|
||||||
|
incorrectly causing the main pipeline to not terminate or terminate too early.
|
||||||
|
|
||||||
|
- Fixed an audio stuttering issue in `FastPitchTTSService`.
|
||||||
|
|
||||||
- Fixed a `BaseOutputTransport` issue that was causing non-audio frames being
|
- Fixed a `BaseOutputTransport` issue that was causing non-audio frames being
|
||||||
processed before the previous audio frames were played. This will allow, for
|
processed before the previous audio frames were played. This will allow, for
|
||||||
example, sending a frame `A` after a `TTSSpeakFrame` and the frame `A` will
|
example, sending a frame `A` after a `TTSSpeakFrame` and the frame `A` will
|
||||||
only be pushed downstream after the audio generated from `TTSSpeakFrame` has
|
only be pushed downstream after the audio generated from `TTSSpeakFrame` has
|
||||||
been spoken.
|
been spoken.
|
||||||
|
|
||||||
|
- Fixed a `DeepgramSTTService` issue that was causing language to be passed as
|
||||||
|
an object instead of a string resulting in the connection to fail.
|
||||||
|
|
||||||
|
## [0.0.51] - 2024-12-16
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed an issue in websocket-based TTS services that was causing infinite
|
||||||
|
reconnections (Cartesia, ElevenLabs, PlayHT and LMNT).
|
||||||
|
|
||||||
## [0.0.50] - 2024-12-11
|
## [0.0.50] - 2024-12-11
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
BSD 2-Clause License
|
BSD 2-Clause License
|
||||||
|
|
||||||
Copyright (c) 2024, Daily
|
Copyright (c) 2024–2025, Daily
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions are met:
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|||||||
56
README.md
56
README.md
@@ -2,7 +2,7 @@
|
|||||||
<img alt="pipecat" width="300px" height="auto" src="https://raw.githubusercontent.com/pipecat-ai/pipecat/main/pipecat.png">
|
<img alt="pipecat" width="300px" height="auto" src="https://raw.githubusercontent.com/pipecat-ai/pipecat/main/pipecat.png">
|
||||||
</div></h1>
|
</div></h1>
|
||||||
|
|
||||||
[](https://pypi.org/project/pipecat-ai) [](https://discord.gg/pipecat) <a href="https://app.commanddash.io/agent/github_pipecat-ai_pipecat"><img src="https://img.shields.io/badge/AI-Code%20Agent-EB9FDA"></a>
|
[](https://pypi.org/project/pipecat-ai)  [](https://docs.pipecat.ai) [](https://discord.gg/pipecat) <a href="https://app.commanddash.io/agent/github_pipecat-ai_pipecat"><img src="https://img.shields.io/badge/AI-Code%20Agent-EB9FDA"></a>
|
||||||
|
|
||||||
Pipecat is an open source Python framework for building voice and multimodal conversational agents. It handles the complex orchestration of AI services, network transport, audio processing, and multimodal interactions, letting you focus on creating engaging experiences.
|
Pipecat is an open source Python framework for building voice and multimodal conversational agents. It handles the complex orchestration of AI services, network transport, audio processing, and multimodal interactions, letting you focus on creating engaging experiences.
|
||||||
|
|
||||||
@@ -53,21 +53,21 @@ To keep things lightweight, only the core framework is included by default. If y
|
|||||||
pip install "pipecat-ai[option,...]"
|
pip install "pipecat-ai[option,...]"
|
||||||
```
|
```
|
||||||
|
|
||||||
Available options include:
|
### Available services
|
||||||
|
|
||||||
| Category | Services | Install Command Example |
|
| Category | Services | Install Command Example |
|
||||||
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
|
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
|
||||||
| Speech-to-Text | [AssemblyAI](https://docs.pipecat.ai/api-reference/services/stt/assemblyai), [Azure](https://docs.pipecat.ai/api-reference/services/stt/azure), [Deepgram](https://docs.pipecat.ai/api-reference/services/stt/deepgram), [Gladia](https://docs.pipecat.ai/api-reference/services/stt/gladia), [Whisper](https://docs.pipecat.ai/api-reference/services/stt/whisper) | `pip install "pipecat-ai[deepgram]"` |
|
| Speech-to-Text | [AssemblyAI](https://docs.pipecat.ai/server/services/stt/assemblyai), [Azure](https://docs.pipecat.ai/server/services/stt/azure), [Deepgram](https://docs.pipecat.ai/server/services/stt/deepgram), [Gladia](https://docs.pipecat.ai/server/services/stt/gladia), [Whisper](https://docs.pipecat.ai/server/services/stt/whisper) | `pip install "pipecat-ai[deepgram]"` |
|
||||||
| LLMs | [Anthropic](https://docs.pipecat.ai/api-reference/services/llm/anthropic), [Azure](https://docs.pipecat.ai/api-reference/services/llm/azure), [Fireworks AI](https://docs.pipecat.ai/api-reference/services/llm/fireworks), [Gemini](https://docs.pipecat.ai/api-reference/services/llm/gemini), [Grok](https://docs.pipecat.ai/api-reference/services/llm/grok), [Groq](https://docs.pipecat.ai/api-reference/services/llm/groq), [NVIDIA NIM](https://docs.pipecat.ai/api-reference/services/llm/nim), [Ollama](https://docs.pipecat.ai/api-reference/services/llm/ollama), [OpenAI](https://docs.pipecat.ai/api-reference/services/llm/openai), [Together AI](https://docs.pipecat.ai/api-reference/services/llm/together) | `pip install "pipecat-ai[openai]"` |
|
| LLMs | [Anthropic](https://docs.pipecat.ai/server/services/llm/anthropic), [Azure](https://docs.pipecat.ai/server/services/llm/azure), [Cerebras](https://docs.pipecat.ai/server/services/llm/cerebras), [DeepSeek](https://docs.pipecat.ai/server/services/llm/deepseek), [Fireworks AI](https://docs.pipecat.ai/server/services/llm/fireworks), [Gemini](https://docs.pipecat.ai/server/services/llm/gemini), [Grok](https://docs.pipecat.ai/server/services/llm/grok), [Groq](https://docs.pipecat.ai/server/services/llm/groq), [NVIDIA NIM](https://docs.pipecat.ai/server/services/llm/nim), [Ollama](https://docs.pipecat.ai/server/services/llm/ollama), [OpenAI](https://docs.pipecat.ai/server/services/llm/openai), [OpenRouter](https://docs.pipecat.ai/server/services/llm/openrouter), [Together AI](https://docs.pipecat.ai/server/services/llm/together) | `pip install "pipecat-ai[openai]"` |
|
||||||
| Text-to-Speech | [AWS](https://docs.pipecat.ai/api-reference/services/tts/aws), [Azure](https://docs.pipecat.ai/api-reference/services/tts/azure), [Cartesia](https://docs.pipecat.ai/api-reference/services/tts/cartesia), [Deepgram](https://docs.pipecat.ai/api-reference/services/tts/deepgram), [ElevenLabs](https://docs.pipecat.ai/api-reference/services/tts/elevenlabs), [Google](https://docs.pipecat.ai/api-reference/services/tts/google), [LMNT](https://docs.pipecat.ai/api-reference/services/tts/lmnt), [OpenAI](https://docs.pipecat.ai/api-reference/services/tts/openai), [PlayHT](https://docs.pipecat.ai/api-reference/services/tts/playht), [Rime](https://docs.pipecat.ai/api-reference/services/tts/rime), [XTTS](https://docs.pipecat.ai/api-reference/services/tts/xtts) | `pip install "pipecat-ai[cartesia]"` |
|
| Text-to-Speech | [AWS](https://docs.pipecat.ai/server/services/tts/aws), [Azure](https://docs.pipecat.ai/server/services/tts/azure), [Cartesia](https://docs.pipecat.ai/server/services/tts/cartesia), [Deepgram](https://docs.pipecat.ai/server/services/tts/deepgram), [ElevenLabs](https://docs.pipecat.ai/server/services/tts/elevenlabs), [Fish](https://docs.pipecat.ai/server/services/tts/fish), [Google](https://docs.pipecat.ai/server/services/tts/google), [LMNT](https://docs.pipecat.ai/server/services/tts/lmnt), [OpenAI](https://docs.pipecat.ai/server/services/tts/openai), [PlayHT](https://docs.pipecat.ai/server/services/tts/playht), [Rime](https://docs.pipecat.ai/server/services/tts/rime), [XTTS](https://docs.pipecat.ai/server/services/tts/xtts) | `pip install "pipecat-ai[cartesia]"` |
|
||||||
| Speech-to-Speech | [Gemini Multimodal Live](https://docs.pipecat.ai/server/services/s2s/gemini), [OpenAI Realtime](https://docs.pipecat.ai/api-reference/services/s2s/openai) | `pip install "pipecat-ai[openai]"` |
|
| Speech-to-Speech | [Gemini Multimodal Live](https://docs.pipecat.ai/server/services/s2s/gemini), [OpenAI Realtime](https://docs.pipecat.ai/server/services/s2s/openai) | `pip install "pipecat-ai[openai]"` |
|
||||||
| Transport | [Daily (WebRTC)](https://docs.pipecat.ai/api-reference/services/transport/daily), WebSocket, Local | `pip install "pipecat-ai[daily]"` |
|
| Transport | [Daily (WebRTC)](https://docs.pipecat.ai/server/services/transport/daily), [FastAPI Websocket](https://docs.pipecat.ai/server/services/transport/fastapi-websocket), [WebSocket Server](https://docs.pipecat.ai/server/services/transport/websocket-server), Local | `pip install "pipecat-ai[daily]"` |
|
||||||
| Video | [Tavus](https://docs.pipecat.ai/api-reference/services/video/tavus), [Simli](https://docs.pipecat.ai/api-reference/services/video/simli) | `pip install "pipecat-ai[tavus,simli]"` |
|
| Video | [Tavus](https://docs.pipecat.ai/server/services/video/tavus), [Simli](https://docs.pipecat.ai/server/services/video/simli) | `pip install "pipecat-ai[tavus,simli]"` |
|
||||||
| Vision & Image | [Moondream](https://docs.pipecat.ai/api-reference/services/vision/moondream), [fal](https://docs.pipecat.ai/api-reference/services/image-generation/fal) | `pip install "pipecat-ai[moondream]"` |
|
| Vision & Image | [Moondream](https://docs.pipecat.ai/server/services/vision/moondream), [fal](https://docs.pipecat.ai/server/services/image-generation/fal) | `pip install "pipecat-ai[moondream]"` |
|
||||||
| Audio Processing | [Silero VAD](https://docs.pipecat.ai/api-reference/utilities/audio/silero-vad-analyzer), [Krisp](https://docs.pipecat.ai/api-reference/utilities/audio/krisp-filter), [Noisereduce](https://docs.pipecat.ai/api-reference/utilities/audio/noisereduce-filter) | `pip install "pipecat-ai[silero]"` |
|
| Audio Processing | [Silero VAD](https://docs.pipecat.ai/server/utilities/audio/silero-vad-analyzer), [Krisp](https://docs.pipecat.ai/server/utilities/audio/krisp-filter), [Koala](https://docs.pipecat.ai/server/utilities/audio/koala-filter), [Noisereduce](https://docs.pipecat.ai/server/utilities/audio/noisereduce-filter) | `pip install "pipecat-ai[silero]"` |
|
||||||
| Analytics & Metrics | [Canonical AI](https://docs.pipecat.ai/api-reference/services/analytics/canonical), [Sentry](https://docs.pipecat.ai/api-reference/services/analytics/sentry) | `pip install "pipecat-ai[canonical]"` |
|
| Analytics & Metrics | [Canonical AI](https://docs.pipecat.ai/server/services/analytics/canonical), [Sentry](https://docs.pipecat.ai/server/services/analytics/sentry) | `pip install "pipecat-ai[canonical]"` |
|
||||||
|
|
||||||
📚 [View full services documentation →](https://docs.pipecat.ai/api-reference/services/supported-services)
|
📚 [View full services documentation →](https://docs.pipecat.ai/server/services/supported-services)
|
||||||
|
|
||||||
## Code examples
|
## Code examples
|
||||||
|
|
||||||
@@ -160,15 +160,24 @@ From the root of this repo, run the following:
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
pip install -r dev-requirements.txt
|
pip install -r dev-requirements.txt
|
||||||
python -m build
|
|
||||||
```
|
```
|
||||||
|
|
||||||
This builds the package. To use the package locally (e.g. to run sample files), run
|
This will install the necessary development dependencies. Also, make sure you install the git pre-commit hooks:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pre-commit install
|
||||||
|
```
|
||||||
|
|
||||||
|
The hooks will just save you time when you submit a PR by making sure your code follows the project rules.
|
||||||
|
|
||||||
|
To use the package locally (e.g. to run sample files), run:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pip install --editable ".[option,...]"
|
pip install --editable ".[option,...]"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `--editable` option makes sure you don't have to run `pip install` again and you can just edit the project files locally.
|
||||||
|
|
||||||
If you want to use this package from another directory, you can run:
|
If you want to use this package from another directory, you can run:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
@@ -180,7 +189,7 @@ pip install "path_to_this_repo[option,...]"
|
|||||||
From the root directory, run:
|
From the root directory, run:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
pytest --doctest-modules --ignore-glob="*to_be_updated*" --ignore-glob=*pipeline_source* src tests
|
pytest
|
||||||
```
|
```
|
||||||
|
|
||||||
## Setting up your editor
|
## Setting up your editor
|
||||||
@@ -197,9 +206,7 @@ You can use [use-package](https://github.com/jwiegley/use-package) to install [e
|
|||||||
:hook ((python-mode . lazy-ruff-mode))
|
:hook ((python-mode . lazy-ruff-mode))
|
||||||
:config
|
:config
|
||||||
(setq lazy-ruff-format-command "ruff format")
|
(setq lazy-ruff-format-command "ruff format")
|
||||||
(setq lazy-ruff-only-format-block t)
|
(setq lazy-ruff-check-command "ruff check --select I"))
|
||||||
(setq lazy-ruff-only-format-region t)
|
|
||||||
(setq lazy-ruff-only-format-buffer t))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`ruff` was installed in the `venv` environment described before, so you should be able to use [pyvenv-auto](https://github.com/ryotaro612/pyvenv-auto) to automatically load that environment inside Emacs.
|
`ruff` was installed in the `venv` environment described before, so you should be able to use [pyvenv-auto](https://github.com/ryotaro612/pyvenv-auto) to automatically load that environment inside Emacs.
|
||||||
@@ -209,7 +216,6 @@ You can use [use-package](https://github.com/jwiegley/use-package) to install [e
|
|||||||
:ensure t
|
:ensure t
|
||||||
:defer t
|
:defer t
|
||||||
:hook ((python-mode . pyvenv-auto-run)))
|
:hook ((python-mode . pyvenv-auto-run)))
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Visual Studio Code
|
### Visual Studio Code
|
||||||
@@ -224,6 +230,16 @@ Install the
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### PyCharm
|
||||||
|
|
||||||
|
`ruff` was installed in the `venv` environment described before, now to enable autoformatting on save, go to `File` -> `Settings` -> `Tools` -> `File Watchers` and add a new watcher with the following settings:
|
||||||
|
|
||||||
|
1. **Name**: `Ruff formatter`
|
||||||
|
2. **File type**: `Python`
|
||||||
|
3. **Working directory**: `$ContentRoot$`
|
||||||
|
4. **Arguments**: `format $FilePath$`
|
||||||
|
5. **Program**: `$PyInterpreterDirectory$/ruff`
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
We welcome contributions from the community! Whether you're fixing bugs, improving documentation, or adding new features, here's how you can help:
|
We welcome contributions from the community! Whether you're fixing bugs, improving documentation, or adding new features, here's how you can help:
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
build~=1.2.1
|
build~=1.2.2
|
||||||
grpcio-tools~=1.65.4
|
grpcio-tools~=1.69.0
|
||||||
pip-tools~=7.4.1
|
pip-tools~=7.4.1
|
||||||
pyright~=1.1.376
|
pre-commit~=4.0.1
|
||||||
pytest~=8.3.2
|
pyright~=1.1.392
|
||||||
ruff~=0.6.7
|
pytest~=8.3.4
|
||||||
setuptools~=72.2.0
|
pytest-asyncio~=0.25.2
|
||||||
|
ruff~=0.9.1
|
||||||
|
setuptools~=75.8.0
|
||||||
setuptools_scm~=8.1.0
|
setuptools_scm~=8.1.0
|
||||||
|
python-dotenv~=1.0.1
|
||||||
|
|||||||
@@ -60,3 +60,27 @@ SIMLI_FACE_ID=...
|
|||||||
|
|
||||||
# Krisp
|
# Krisp
|
||||||
KRISP_MODEL_PATH=...
|
KRISP_MODEL_PATH=...
|
||||||
|
|
||||||
|
# DeepSeek
|
||||||
|
DEEPSEEK_API_KEY=...
|
||||||
|
|
||||||
|
# Groq
|
||||||
|
GROQ_API_KEY=...
|
||||||
|
|
||||||
|
# Grok
|
||||||
|
GROK_API_KEY=...
|
||||||
|
|
||||||
|
# Together.ai
|
||||||
|
TOGETHER_API_KEY=...
|
||||||
|
|
||||||
|
# Cerebras
|
||||||
|
CEREBRAS_API_KEY=...
|
||||||
|
|
||||||
|
# Fish Audio
|
||||||
|
FISH_API_KEY=...
|
||||||
|
|
||||||
|
# Assembly AI
|
||||||
|
ASSEMBLYAI_API_KEY=...
|
||||||
|
|
||||||
|
# OpenRouter
|
||||||
|
OPENROUTER_API_KEY=...
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ Next, follow the steps in the README for each demo.
|
|||||||
| [Translation Chatbot](translation-chatbot) | Listens for user speech, then translates that speech to Spanish and speaks the translation back. Demonstrates multi-participant use-cases. | Deepgram, Azure, OpenAI, Daily, Daily Prebuilt UI |
|
| [Translation Chatbot](translation-chatbot) | Listens for user speech, then translates that speech to Spanish and speaks the translation back. Demonstrates multi-participant use-cases. | Deepgram, Azure, OpenAI, Daily, Daily Prebuilt UI |
|
||||||
| [Moondream Chatbot](moondream-chatbot) | Demonstrates how to add vision capabilities to GPT4. **Note: works best with a GPU** | Deepgram, ElevenLabs, OpenAI, Moondream, Daily, Daily Prebuilt UI |
|
| [Moondream Chatbot](moondream-chatbot) | Demonstrates how to add vision capabilities to GPT4. **Note: works best with a GPU** | Deepgram, ElevenLabs, OpenAI, Moondream, Daily, Daily Prebuilt UI |
|
||||||
| [Patient intake](patient-intake) | A chatbot that can call functions in response to user input. | Deepgram, ElevenLabs, OpenAI, Daily, Daily Prebuilt UI |
|
| [Patient intake](patient-intake) | A chatbot that can call functions in response to user input. | Deepgram, ElevenLabs, OpenAI, Daily, Daily Prebuilt UI |
|
||||||
| [Dialin Chatbot](dialin-chatbot) | A chatbot that connects to an incoming phone call from Daily or Twilio. | Deepgram, ElevenLabs, OpenAI, Daily, Twilio |
|
| [Phone Chatbot](phone-chatbot) | A chatbot that connects to PSTN/SIP phone calls, powered by Daily or Twilio. | Deepgram, ElevenLabs, OpenAI, Daily, Twilio |
|
||||||
| [Twilio Chatbot](twilio-chatbot) | A chatbot that connects to an incoming phone call from Twilio. | Deepgram, ElevenLabs, OpenAI, Daily, Twilio |
|
| [Twilio Chatbot](twilio-chatbot) | A chatbot that connects to an incoming phone call from Twilio. | Deepgram, ElevenLabs, OpenAI, Daily, Twilio |
|
||||||
| [studypal](studypal) | A chatbot to have a conversation about any article on the web | |
|
| [studypal](studypal) | A chatbot to have a conversation about any article on the web | |
|
||||||
| [WebSocket Chatbot Server](websocket-server) | A real-time websocket server that handles audio streaming and bot interactions with speech-to-text and text-to-speech capabilities | `python-websockets`, `openai`, `deepgram`, `silero-tts`, `numpy` |
|
| [WebSocket Chatbot Server](websocket-server) | A real-time websocket server that handles audio streaming and bot interactions with speech-to-text and text-to-speech capabilities. | Cartesia, Deepgram, OpenAI, Websockets |
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> These example projects use Daily as a WebRTC transport and can be joined using their hosted Prebuilt UI.
|
> These example projects use Daily as a WebRTC transport and can be joined using their hosted Prebuilt UI.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -15,7 +15,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import EndFrame, LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -97,7 +97,7 @@ async def main():
|
|||||||
call completion, CanonicalMetrics will send the audio buffer to Canonical for
|
call completion, CanonicalMetrics will send the audio buffer to Canonical for
|
||||||
analysis. Visit https://voice.canonical.chat to learn more.
|
analysis. Visit https://voice.canonical.chat to learn more.
|
||||||
"""
|
"""
|
||||||
audio_buffer_processor = AudioBufferProcessor()
|
audio_buffer_processor = AudioBufferProcessor(num_channels=2)
|
||||||
canonical = CanonicalMetricsService(
|
canonical = CanonicalMetricsService(
|
||||||
audio_buffer_processor=audio_buffer_processor,
|
audio_buffer_processor=audio_buffer_processor,
|
||||||
aiohttp_session=session,
|
aiohttp_session=session,
|
||||||
@@ -105,6 +105,7 @@ async def main():
|
|||||||
call_id=str(uuid.uuid4()),
|
call_id=str(uuid.uuid4()),
|
||||||
assistant="pipecat-chatbot",
|
assistant="pipecat-chatbot",
|
||||||
assistant_speaks_first=True,
|
assistant_speaks_first=True,
|
||||||
|
context=context,
|
||||||
)
|
)
|
||||||
pipeline = Pipeline(
|
pipeline = Pipeline(
|
||||||
[
|
[
|
||||||
@@ -124,7 +125,7 @@ async def main():
|
|||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
@transport.event_handler("on_participant_left")
|
@transport.event_handler("on_participant_left")
|
||||||
async def on_participant_left(transport, participant, reason):
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -53,4 +53,3 @@ async def configure(aiohttp_session: aiohttp.ClientSession):
|
|||||||
token = await daily_rest_helper.get_token(url, expiry_time)
|
token = await daily_rest_helper.get_token(url, expiry_time)
|
||||||
|
|
||||||
return (url, token)
|
return (url, token)
|
||||||
return (url, token)
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiofiles
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import datetime
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import datetime
|
|
||||||
import wave
|
import wave
|
||||||
|
|
||||||
|
import aiofiles
|
||||||
|
import aiohttp
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import EndFrame, LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -134,7 +134,7 @@ async def main():
|
|||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
@transport.event_handler("on_participant_left")
|
@transport.event_handler("on_participant_left")
|
||||||
async def on_participant_left(transport, participant, reason):
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
|
import argparse
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.frames.frames import LLMMessagesFrame, EndFrame
|
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
from pipecat.services.openai import OpenAILLMService
|
|
||||||
from pipecat.services.elevenlabs import ElevenLabsTTSService
|
from pipecat.services.elevenlabs import ElevenLabsTTSService
|
||||||
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -76,7 +75,7 @@ async def main(room_url: str, token: str):
|
|||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
@transport.event_handler("on_participant_left")
|
@transport.event_handler("on_participant_left")
|
||||||
async def on_participant_left(transport, participant, reason):
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
|||||||
@@ -1,29 +1,27 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import argparse
|
import argparse
|
||||||
import subprocess
|
|
||||||
import os
|
import os
|
||||||
|
import subprocess
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
|
|
||||||
from fastapi import FastAPI, Request, HTTPException
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from fastapi import FastAPI, HTTPException, Request
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
|
||||||
from pipecat.transports.services.helpers.daily_rest import (
|
from pipecat.transports.services.helpers.daily_rest import (
|
||||||
DailyRESTHelper,
|
DailyRESTHelper,
|
||||||
DailyRoomObject,
|
DailyRoomObject,
|
||||||
DailyRoomProperties,
|
|
||||||
DailyRoomParams,
|
DailyRoomParams,
|
||||||
|
DailyRoomProperties,
|
||||||
)
|
)
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ import os
|
|||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
import modal
|
import modal
|
||||||
|
from bot import _voice_bot_process
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from bot import _voice_bot_process
|
|
||||||
|
|
||||||
MAX_SESSION_TIME = 15 * 60 # 15 minutes
|
MAX_SESSION_TIME = 15 * 60 # 15 minutes
|
||||||
|
|
||||||
app = modal.App("pipecat-modal")
|
app = modal.App("pipecat-modal")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
async def main(room_url: str, token: str):
|
async def main(room_url: str, token: str):
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import EndFrame, LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -75,7 +75,7 @@ async def main(room_url: str, token: str):
|
|||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
@transport.event_handler("on_participant_left")
|
@transport.event_handler("on_participant_left")
|
||||||
async def on_participant_left(transport, participant, reason):
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
python-dotenv==1.0.1
|
python-dotenv==1.0.1
|
||||||
modal==0.65.48
|
modal==0.71.3
|
||||||
pipecat-ai[daily,silero,cartesia,openai]==0.0.48
|
pipecat-ai[daily,silero,cartesia,openai]==0.0.52
|
||||||
fastapi==0.115.4
|
fastapi==0.115.6
|
||||||
aiohttp==3.11.9
|
aiohttp==3.11.11
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
<div align="center">
|
|
||||||
<img alt="pipecat" width="300px" height="auto" src="image.png">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
# Dialin example
|
|
||||||
|
|
||||||
Example project that demonstrates how to add phone number dialin to your Pipecat bots. We include examples for both Daily (`bot_daily.py`) and Twilio (`bot_twilio.py`), depending on who you want to use as a phone vendor.
|
|
||||||
|
|
||||||
- 🔁 Transport: Daily WebRTC
|
|
||||||
- 💬 Speech-to-Text: Deepgram via Daily transport
|
|
||||||
- 🤖 LLM: GPT4-o / OpenAI
|
|
||||||
- 🔉 Text-to-Speech: ElevenLabs
|
|
||||||
|
|
||||||
#### Should I use Daily or Twilio as a vendor?
|
|
||||||
|
|
||||||
If you're starting from scratch, using Daily to provision phone numbers alongside Daily as a transport offers some convenience (such as automatic call forwarding.)
|
|
||||||
|
|
||||||
If you already have Twilio numbers and workflows that you want to connect to your Pipecat bots, there is some additional configuration required (you'll need to create a `on_dialin_ready` and use the Twilio client to trigger the forward.)
|
|
||||||
|
|
||||||
You can read more about this, as well as see respective walkthroughs in our docs.
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
|
|
||||||
```shell
|
|
||||||
# Install the requirements
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
# Setup your env
|
|
||||||
mv env.example .env
|
|
||||||
```
|
|
||||||
|
|
||||||
## Using Daily numbers
|
|
||||||
|
|
||||||
Run `bot_runner.py` to handle incoming HTTP requests:
|
|
||||||
|
|
||||||
`python bot_runner.py --host localhost`
|
|
||||||
|
|
||||||
Then target the following URL:
|
|
||||||
|
|
||||||
`POST /daily_start_bot`
|
|
||||||
|
|
||||||
For more configuration options, please consult Daily's API documentation.
|
|
||||||
|
|
||||||
|
|
||||||
## Using Twilio numbers
|
|
||||||
|
|
||||||
As above, but target the following URL:
|
|
||||||
|
|
||||||
`POST /twilio_start_bot`
|
|
||||||
|
|
||||||
For more configuration options, please consult Twilio's API documentation.
|
|
||||||
|
|
||||||
## Deployment example
|
|
||||||
|
|
||||||
A Dockerfile is included in this demo for convenience. Here is an example of how to build and deploy your bot to [fly.io](https://fly.io).
|
|
||||||
|
|
||||||
*Please note: This demo spawns agents as subprocesses for convenience / demonstration purposes. You would likely not want to do this in production as it would limit concurrency to available system resources. For more information on how to deploy your bots using VMs, refer to the Pipecat documentation.*
|
|
||||||
|
|
||||||
### Build the docker image
|
|
||||||
|
|
||||||
`docker build -t tag:project .`
|
|
||||||
|
|
||||||
### Launch the fly project
|
|
||||||
|
|
||||||
`mv fly.example.toml fly.toml`
|
|
||||||
|
|
||||||
`fly launch` (using the included fly.toml)
|
|
||||||
|
|
||||||
### Setup your secrets on Fly
|
|
||||||
|
|
||||||
Set the necessary secrets (found in `env.example`)
|
|
||||||
|
|
||||||
`fly secrets set DAILY_API_KEY=... OPENAI_API_KEY=... ELEVENLABS_API_KEY=... ELEVENLABS_VOICE_ID=...`
|
|
||||||
|
|
||||||
If you're using Twilio as a number vendor:
|
|
||||||
|
|
||||||
`fly secrets set TWILIO_ACCOUNT_SID=... TWILIO_AUTH_TOKEN=...`
|
|
||||||
|
|
||||||
### Deploy!
|
|
||||||
|
|
||||||
`fly deploy`
|
|
||||||
|
|
||||||
## Need to do something more advanced?
|
|
||||||
|
|
||||||
This demo covers the basics of bot telephony. If you want to know more about working with PSTN / SIP, please ping us on [Discord](https://discord.gg/pipecat).
|
|
||||||
@@ -1,26 +1,24 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pipecat.frames.frames import EndFrame, TTSSpeakFrame
|
import aiohttp
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from dotenv import load_dotenv
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from loguru import logger
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
|
||||||
|
|
||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from loguru import logger
|
from pipecat.frames.frames import EndFrame, TTSSpeakFrame
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from dotenv import load_dotenv
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineTask
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from pipecat.frames.frames import EndFrame, TTSSpeakFrame
|
from pipecat.frames.frames import EndFrame, TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -17,10 +19,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.transports.base_transport import TransportParams
|
from pipecat.transports.base_transport import TransportParams
|
||||||
from pipecat.transports.local.audio import LocalAudioTransport
|
from pipecat.transports.local.audio import LocalAudioTransport
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from livekit import api
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from pipecat.frames.frames import TextFrame
|
from pipecat.frames.frames import TextFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
@@ -12,12 +15,6 @@ from pipecat.pipeline.task import PipelineTask
|
|||||||
from pipecat.services.cartesia import CartesiaTTSService
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.transports.services.livekit import LiveKitParams, LiveKitTransport
|
from pipecat.transports.services.livekit import LiveKitParams, LiveKitTransport
|
||||||
|
|
||||||
from livekit import api
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pipecat.frames.frames import EndFrame, TTSSpeakFrame
|
import aiohttp
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from dotenv import load_dotenv
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from loguru import logger
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
|
||||||
from pipecat.services.riva import FastPitchTTSService
|
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
|
||||||
|
|
||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from loguru import logger
|
from pipecat.frames.frames import EndFrame, TTSSpeakFrame
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from dotenv import load_dotenv
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineTask
|
||||||
|
from pipecat.services.riva import FastPitchTTSService
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import EndFrame, LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame, LLMMessagesFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -17,12 +21,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import EndFrame, TextFrame
|
from pipecat.frames.frames import EndFrame, TextFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -16,12 +20,6 @@ from pipecat.pipeline.task import PipelineTask
|
|||||||
from pipecat.services.fal import FalImageGenService
|
from pipecat.services.fal import FalImageGenService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,16 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from pipecat.frames.frames import TextFrame
|
from pipecat.frames.frames import TextFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -19,10 +21,6 @@ from pipecat.services.fal import FalImageGenService
|
|||||||
from pipecat.transports.base_transport import TransportParams
|
from pipecat.transports.base_transport import TransportParams
|
||||||
from pipecat.transports.local.tk import TkLocalTransport
|
from pipecat.transports.local.tk import TkLocalTransport
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -8,27 +8,24 @@
|
|||||||
# This example broken on latest pipecat and needs updating.
|
# This example broken on latest pipecat and needs updating.
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pipecat.pipeline.merge_pipeline import SequentialMergePipeline
|
import aiohttp
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import EndPipeFrame, LLMMessagesFrame, TextFrame
|
from pipecat.frames.frames import EndPipeFrame, LLMMessagesFrame, TextFrame
|
||||||
|
from pipecat.pipeline.merge_pipeline import SequentialMergePipeline
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from pipecat.pipeline.task import PipelineTask
|
||||||
from pipecat.services.azure import AzureLLMService, AzureTTSService
|
from pipecat.services.azure import AzureLLMService, AzureTTSService
|
||||||
from pipecat.services.elevenlabs import ElevenLabsTTSService
|
from pipecat.services.elevenlabs import ElevenLabsTTSService
|
||||||
from pipecat.services.transport_services import TransportServiceOutput
|
from pipecat.services.transport_services import TransportServiceOutput
|
||||||
from pipecat.services.transports.daily_transport import DailyTransport
|
from pipecat.services.transports.daily_transport import DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
DataFrame,
|
DataFrame,
|
||||||
Frame,
|
Frame,
|
||||||
@@ -22,19 +25,13 @@ from pipecat.pipeline.pipeline import Pipeline
|
|||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.sync_parallel_pipeline import SyncParallelPipeline
|
from pipecat.pipeline.sync_parallel_pipeline import SyncParallelPipeline
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from pipecat.pipeline.task import PipelineTask
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
|
||||||
from pipecat.processors.aggregators.sentence import SentenceAggregator
|
from pipecat.processors.aggregators.sentence import SentenceAggregator
|
||||||
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.services.cartesia import CartesiaHttpTTSService
|
from pipecat.services.cartesia import CartesiaHttpTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService
|
|
||||||
from pipecat.services.fal import FalImageGenService
|
from pipecat.services.fal import FalImageGenService
|
||||||
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -56,6 +53,8 @@ class MonthPrepender(FrameProcessor):
|
|||||||
self.prepend_to_next_text_frame = False
|
self.prepend_to_next_text_frame = False
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, MonthFrame):
|
if isinstance(frame, MonthFrame):
|
||||||
self.most_recent_month = frame.month
|
self.most_recent_month = frame.month
|
||||||
elif self.prepend_to_next_text_frame and isinstance(frame, TextFrame):
|
elif self.prepend_to_next_text_frame and isinstance(frame, TextFrame):
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
Frame,
|
Frame,
|
||||||
|
LLMMessagesFrame,
|
||||||
OutputAudioRawFrame,
|
OutputAudioRawFrame,
|
||||||
|
TextFrame,
|
||||||
TTSAudioRawFrame,
|
TTSAudioRawFrame,
|
||||||
URLImageRawFrame,
|
URLImageRawFrame,
|
||||||
LLMMessagesFrame,
|
|
||||||
TextFrame,
|
|
||||||
)
|
)
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -26,15 +28,11 @@ from pipecat.pipeline.task import PipelineTask
|
|||||||
from pipecat.processors.aggregators.sentence import SentenceAggregator
|
from pipecat.processors.aggregators.sentence import SentenceAggregator
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.services.cartesia import CartesiaHttpTTSService
|
from pipecat.services.cartesia import CartesiaHttpTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService
|
|
||||||
from pipecat.services.fal import FalImageGenService
|
from pipecat.services.fal import FalImageGenService
|
||||||
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.base_transport import TransportParams
|
from pipecat.transports.base_transport import TransportParams
|
||||||
from pipecat.transports.local.tk import TkLocalTransport, TkOutputTransport
|
from pipecat.transports.local.tk import TkLocalTransport, TkOutputTransport
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -62,6 +60,8 @@ async def main():
|
|||||||
self.text = ""
|
self.text = ""
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, TextFrame):
|
if isinstance(frame, TextFrame):
|
||||||
self.text = frame.text
|
self.text = frame.text
|
||||||
await self.push_frame(frame, direction)
|
await self.push_frame(frame, direction)
|
||||||
@@ -73,6 +73,8 @@ async def main():
|
|||||||
self.frame = None
|
self.frame = None
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, TTSAudioRawFrame):
|
if isinstance(frame, TTSAudioRawFrame):
|
||||||
self.audio.extend(frame.audio)
|
self.audio.extend(frame.audio)
|
||||||
self.frame = OutputAudioRawFrame(
|
self.frame = OutputAudioRawFrame(
|
||||||
@@ -86,6 +88,8 @@ async def main():
|
|||||||
self.frame = None
|
self.frame = None
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, URLImageRawFrame):
|
if isinstance(frame, URLImageRawFrame):
|
||||||
self.frame = frame
|
self.frame = frame
|
||||||
await self.push_frame(frame, direction)
|
await self.push_frame(frame, direction)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import Frame, LLMMessagesFrame, MetricsFrame
|
from pipecat.frames.frames import EndFrame, Frame, MetricsFrame
|
||||||
from pipecat.metrics.metrics import (
|
from pipecat.metrics.metrics import (
|
||||||
LLMUsageMetricsData,
|
LLMUsageMetricsData,
|
||||||
ProcessingMetricsData,
|
ProcessingMetricsData,
|
||||||
@@ -47,9 +47,7 @@ class MetricsLogger(FrameProcessor):
|
|||||||
elif isinstance(d, LLMUsageMetricsData):
|
elif isinstance(d, LLMUsageMetricsData):
|
||||||
tokens = d.value
|
tokens = d.value
|
||||||
print(
|
print(
|
||||||
f"!!! MetricsFrame: {frame}, tokens: {
|
f"!!! MetricsFrame: {frame}, tokens: {tokens.prompt_tokens}, characters: {tokens.completion_tokens}"
|
||||||
tokens.prompt_tokens}, characters: {
|
|
||||||
tokens.completion_tokens}"
|
|
||||||
)
|
)
|
||||||
elif isinstance(d, TTSUsageMetricsData):
|
elif isinstance(d, TTSUsageMetricsData):
|
||||||
print(f"!!! MetricsFrame: {frame}, characters: {d.value}")
|
print(f"!!! MetricsFrame: {frame}, characters: {d.value}")
|
||||||
@@ -113,7 +111,11 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,33 +1,36 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import Frame, OutputImageRawFrame, SystemFrame, TextFrame
|
from pipecat.frames.frames import (
|
||||||
|
BotStartedSpeakingFrame,
|
||||||
|
BotStoppedSpeakingFrame,
|
||||||
|
EndFrame,
|
||||||
|
Frame,
|
||||||
|
OutputImageRawFrame,
|
||||||
|
TextFrame,
|
||||||
|
)
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.services.cartesia import CartesiaHttpTTSService
|
from pipecat.services.cartesia import CartesiaHttpTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from pipecat.transports.services.daily import DailyParams
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
@@ -47,7 +50,9 @@ class ImageSyncAggregator(FrameProcessor):
|
|||||||
self._waiting_image_bytes = self._waiting_image.tobytes()
|
self._waiting_image_bytes = self._waiting_image.tobytes()
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
if not isinstance(frame, SystemFrame) and direction == FrameDirection.DOWNSTREAM:
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
|
if isinstance(frame, BotStartedSpeakingFrame):
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
OutputImageRawFrame(
|
OutputImageRawFrame(
|
||||||
image=self._speaking_image_bytes,
|
image=self._speaking_image_bytes,
|
||||||
@@ -55,7 +60,8 @@ class ImageSyncAggregator(FrameProcessor):
|
|||||||
format=self._speaking_image_format,
|
format=self._speaking_image_format,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
await self.push_frame(frame)
|
|
||||||
|
elif isinstance(frame, BotStoppedSpeakingFrame):
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
OutputImageRawFrame(
|
OutputImageRawFrame(
|
||||||
image=self._waiting_image_bytes,
|
image=self._waiting_image_bytes,
|
||||||
@@ -63,7 +69,7 @@ class ImageSyncAggregator(FrameProcessor):
|
|||||||
format=self._waiting_image_format,
|
format=self._waiting_image_format,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
await self.push_frame(frame)
|
await self.push_frame(frame)
|
||||||
|
|
||||||
|
|
||||||
@@ -111,16 +117,24 @@ async def main():
|
|||||||
pipeline = Pipeline(
|
pipeline = Pipeline(
|
||||||
[
|
[
|
||||||
transport.input(),
|
transport.input(),
|
||||||
image_sync_aggregator,
|
|
||||||
context_aggregator.user(),
|
context_aggregator.user(),
|
||||||
llm,
|
llm,
|
||||||
tts,
|
tts,
|
||||||
|
image_sync_aggregator,
|
||||||
transport.output(),
|
transport.output(),
|
||||||
context_aggregator.assistant(),
|
context_aggregator.assistant(),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline)
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
@@ -128,6 +142,10 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
await task.queue_frames([TextFrame(f"Hi there {participant_name}!")])
|
await task.queue_frames([TextFrame(f"Hi there {participant_name}!")])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
await runner.run(task)
|
await runner.run(task)
|
||||||
|
|||||||
@@ -1,30 +1,28 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.audio.vad.silero import SileroVAD
|
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
|
from pipecat.processors.audio.vad.silero import SileroVAD
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -92,7 +90,11 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -19,12 +23,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -90,7 +88,11 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -78,13 +78,25 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -9,9 +9,17 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
|
||||||
|
from langchain_community.chat_message_histories import ChatMessageHistory
|
||||||
|
from langchain_core.chat_history import BaseChatMessageHistory
|
||||||
|
from langchain_core.runnables.history import RunnableWithMessageHistory
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame, LLMMessagesFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -23,18 +31,6 @@ from pipecat.processors.frameworks.langchain import LangchainProcessor
|
|||||||
from pipecat.services.cartesia import CartesiaTTSService
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
||||||
from langchain_community.chat_message_histories import ChatMessageHistory
|
|
||||||
from langchain_core.chat_history import BaseChatMessageHistory
|
|
||||||
from langchain_core.runnables.history import RunnableWithMessageHistory
|
|
||||||
from langchain_openai import ChatOpenAI
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
|
||||||
@@ -105,7 +101,15 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
@@ -118,6 +122,10 @@ async def main():
|
|||||||
messages = [({"content": "Please briefly introduce yourself to the user."})]
|
messages = [({"content": "Please briefly introduce yourself to the user."})]
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([LLMMessagesFrame(messages)])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
await runner.run(task)
|
await runner.run(task)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -16,7 +16,7 @@ from runner import configure
|
|||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
BotInterruptionFrame,
|
BotInterruptionFrame,
|
||||||
LLMMessagesFrame,
|
EndFrame,
|
||||||
StopInterruptionFrame,
|
StopInterruptionFrame,
|
||||||
UserStartedSpeakingFrame,
|
UserStartedSpeakingFrame,
|
||||||
UserStoppedSpeakingFrame,
|
UserStoppedSpeakingFrame,
|
||||||
@@ -80,7 +80,15 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@stt.event_handler("on_speech_started")
|
@stt.event_handler("on_speech_started")
|
||||||
async def on_speech_started(stt, *args, **kwargs):
|
async def on_speech_started(stt, *args, **kwargs):
|
||||||
@@ -94,7 +102,11 @@ async def main():
|
|||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -73,13 +73,25 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -11,14 +11,14 @@ import sys
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
|
||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
from pipecat.services.elevenlabs import ElevenLabsTTSService
|
from pipecat.services.elevenlabs import ElevenLabsTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
@@ -88,7 +88,11 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
105
examples/foundational/07e-interruptible-playht-http.py
Normal file
105
examples/foundational/07e-interruptible-playht-http.py
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024–2025, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import EndFrame
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
|
from pipecat.services.openai import OpenAILLMService
|
||||||
|
from pipecat.services.playht import PlayHTHttpTTSService
|
||||||
|
from pipecat.transcriptions.language import Language
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
logger.remove(0)
|
||||||
|
logger.add(sys.stderr, level="DEBUG")
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
(room_url, token) = await configure(session)
|
||||||
|
|
||||||
|
transport = DailyTransport(
|
||||||
|
room_url,
|
||||||
|
token,
|
||||||
|
"Respond bot",
|
||||||
|
DailyParams(
|
||||||
|
audio_out_enabled=True,
|
||||||
|
transcription_enabled=True,
|
||||||
|
vad_enabled=True,
|
||||||
|
vad_analyzer=SileroVADAnalyzer(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
tts = PlayHTHttpTTSService(
|
||||||
|
user_id=os.getenv("PLAYHT_USER_ID"),
|
||||||
|
api_key=os.getenv("PLAYHT_API_KEY"),
|
||||||
|
voice_url="s3://voice-cloning-zero-shot/d9ff78ba-d016-47f6-b0ef-dd630f59414e/female-cs/manifest.json",
|
||||||
|
)
|
||||||
|
|
||||||
|
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. Your output will be converted to audio so don't include special characters in your answers. Respond to what the user said in a creative and helpful way.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = OpenAILLMContext(messages)
|
||||||
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
|
||||||
|
pipeline = Pipeline(
|
||||||
|
[
|
||||||
|
transport.input(), # Transport user input
|
||||||
|
context_aggregator.user(), # User responses
|
||||||
|
llm, # LLM
|
||||||
|
tts, # TTS
|
||||||
|
transport.output(), # Transport bot output
|
||||||
|
context_aggregator.assistant(), # Assistant spoken responses
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@transport.event_handler("on_first_participant_joined")
|
||||||
|
async def on_first_participant_joined(transport, participant):
|
||||||
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
|
# Kick off the conversation.
|
||||||
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
await runner.run(task)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -91,7 +91,11 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -18,13 +22,6 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
|||||||
from pipecat.services.azure import AzureLLMService, AzureSTTService, AzureTTSService
|
from pipecat.services.azure import AzureLLMService, AzureSTTService, AzureTTSService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -85,14 +82,26 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -11,14 +11,14 @@ import sys
|
|||||||
import aiohttp
|
import aiohttp
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
|
||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
from pipecat.services.openai import OpenAILLMService, OpenAITTSService
|
from pipecat.services.openai import OpenAILLMService, OpenAITTSService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
@@ -70,14 +70,26 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -19,13 +24,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openpipe import OpenPipeLLMService
|
from pipecat.services.openpipe import OpenPipeLLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
import time
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -82,14 +80,26 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, params=PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -19,12 +23,6 @@ from pipecat.services.openai import OpenAILLMService
|
|||||||
from pipecat.services.xtts import XTTSService
|
from pipecat.services.xtts import XTTSService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -76,14 +74,26 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import EndFrame, LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -79,14 +79,22 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
# Register an event handler to exit the application when the user leaves.
|
# Register an event handler to exit the application when the user leaves.
|
||||||
@transport.event_handler("on_participant_left")
|
@transport.event_handler("on_participant_left")
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -19,12 +23,6 @@ from pipecat.services.lmnt import LmntTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -73,14 +71,26 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -90,7 +90,10 @@ async def main():
|
|||||||
task = PipelineTask(
|
task = PipelineTask(
|
||||||
pipeline,
|
pipeline,
|
||||||
PipelineParams(
|
PipelineParams(
|
||||||
allow_interruptions=True, enable_metrics=True, enable_usage_metrics=True
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -98,7 +101,11 @@ async def main():
|
|||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -80,14 +80,26 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -22,6 +22,7 @@ from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
|||||||
from pipecat.services.deepgram import DeepgramSTTService
|
from pipecat.services.deepgram import DeepgramSTTService
|
||||||
from pipecat.services.google import GoogleTTSService
|
from pipecat.services.google import GoogleTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
|
from pipecat.transcriptions.language import Language
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
@@ -50,8 +51,8 @@ async def main():
|
|||||||
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
stt = DeepgramSTTService(api_key=os.getenv("DEEPGRAM_API_KEY"))
|
||||||
|
|
||||||
tts = GoogleTTSService(
|
tts = GoogleTTSService(
|
||||||
voice_id="en-US-Neural2-J",
|
voice_id="en-US-Journey-F",
|
||||||
params=GoogleTTSService.InputParams(language="en-US", rate="1.05"),
|
params=GoogleTTSService.InputParams(language=Language.EN_US),
|
||||||
)
|
)
|
||||||
|
|
||||||
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
|
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
|
||||||
@@ -78,14 +79,26 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -79,14 +79,26 @@ async def main():
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -13,19 +13,16 @@ from dotenv import load_dotenv
|
|||||||
from loguru import logger
|
from loguru import logger
|
||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.audio.filters.krisp_filter import KrispFilter
|
||||||
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.llm_response import (
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
LLMAssistantResponseAggregator,
|
|
||||||
LLMUserResponseAggregator,
|
|
||||||
)
|
|
||||||
from pipecat.services.deepgram import DeepgramSTTService, DeepgramTTSService
|
from pipecat.services.deepgram import DeepgramSTTService, DeepgramTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
from pipecat.vad.silero import SileroVADAnalyzer
|
from pipecat.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.audio.filters.krisp_filter import KrispFilter
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
@@ -63,28 +60,40 @@ async def main():
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
tma_in = LLMUserResponseAggregator(messages)
|
context = OpenAILLMContext(messages)
|
||||||
tma_out = LLMAssistantResponseAggregator(messages)
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
|
||||||
pipeline = Pipeline(
|
pipeline = Pipeline(
|
||||||
[
|
[
|
||||||
transport.input(), # Transport user input
|
transport.input(), # Transport user input
|
||||||
stt, # STT
|
stt, # STT
|
||||||
tma_in, # User responses
|
context_aggregator.user(), # User responses
|
||||||
llm, # LLM
|
llm, # LLM
|
||||||
tts, # TTS
|
tts, # TTS
|
||||||
transport.output(), # Transport bot output
|
transport.output(), # Transport bot output
|
||||||
tma_out, # Assistant spoken responses
|
context_aggregator.assistant(), # Assistant spoken responses
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
task = PipelineTask(pipeline, PipelineParams(allow_interruptions=True))
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -89,7 +89,11 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,7 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -81,7 +81,11 @@ async def main():
|
|||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import google.ai.generativelanguage as glm
|
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
import google.ai.generativelanguage as glm
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
|
||||||
from pipecat.services.google import GoogleLLMService
|
|
||||||
from pipecat.processors.frame_processor import FrameProcessor
|
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
LLMFullResponseStartFrame,
|
EndFrame,
|
||||||
LLMFullResponseEndFrame,
|
|
||||||
InputAudioRawFrame,
|
|
||||||
Frame,
|
Frame,
|
||||||
|
InputAudioRawFrame,
|
||||||
|
LLMFullResponseEndFrame,
|
||||||
|
LLMFullResponseStartFrame,
|
||||||
StartInterruptionFrame,
|
StartInterruptionFrame,
|
||||||
TextFrame,
|
TextFrame,
|
||||||
TranscriptionFrame,
|
TranscriptionFrame,
|
||||||
UserStartedSpeakingFrame,
|
UserStartedSpeakingFrame,
|
||||||
UserStoppedSpeakingFrame,
|
UserStoppedSpeakingFrame,
|
||||||
)
|
)
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
|
from pipecat.processors.frame_processor import FrameProcessor
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
|
from pipecat.services.google import GoogleLLMService
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
@@ -82,6 +82,8 @@ class UserAudioCollector(FrameProcessor):
|
|||||||
self._user_speaking = False
|
self._user_speaking = False
|
||||||
|
|
||||||
async def process_frame(self, frame, direction):
|
async def process_frame(self, frame, direction):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, TranscriptionFrame):
|
if isinstance(frame, TranscriptionFrame):
|
||||||
# We could gracefully handle both audio input and text/transcription input ...
|
# We could gracefully handle both audio input and text/transcription input ...
|
||||||
# but let's leave that as an exercise to the reader. :-)
|
# but let's leave that as an exercise to the reader. :-)
|
||||||
@@ -124,6 +126,7 @@ class TranscriptExtractor(FrameProcessor):
|
|||||||
self._accumulating_transcript = False
|
self._accumulating_transcript = False
|
||||||
|
|
||||||
async def process_frame(self, frame, direction):
|
async def process_frame(self, frame, direction):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
if isinstance(frame, LLMFullResponseStartFrame):
|
if isinstance(frame, LLMFullResponseStartFrame):
|
||||||
self._processing_llm_response = True
|
self._processing_llm_response = True
|
||||||
self._accumulating_transcript = True
|
self._accumulating_transcript = True
|
||||||
@@ -177,6 +180,8 @@ class TanscriptionContextFixup(FrameProcessor):
|
|||||||
self._context.messages[-1].parts[-1].text += f"\n\n{marker}\n{self._transcript}\n"
|
self._context.messages[-1].parts[-1].text += f"\n\n{marker}\n{self._transcript}\n"
|
||||||
|
|
||||||
async def process_frame(self, frame, direction):
|
async def process_frame(self, frame, direction):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, MagicDemoTranscriptionFrame):
|
if isinstance(frame, MagicDemoTranscriptionFrame):
|
||||||
self._transcript = frame.text
|
self._transcript = frame.text
|
||||||
elif isinstance(frame, LLMFullResponseEndFrame) or isinstance(
|
elif isinstance(frame, LLMFullResponseEndFrame) or isinstance(
|
||||||
@@ -264,6 +269,10 @@ async def main():
|
|||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
await runner.run(task)
|
await runner.run(task)
|
||||||
|
|||||||
103
examples/foundational/07t-interruptible-fish.py
Normal file
103
examples/foundational/07t-interruptible-fish.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024–2025, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import EndFrame
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
|
from pipecat.services.fish import FishAudioTTSService
|
||||||
|
from pipecat.services.openai import OpenAILLMService
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
logger.remove(0)
|
||||||
|
logger.add(sys.stderr, level="DEBUG")
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
(room_url, token) = await configure(session)
|
||||||
|
|
||||||
|
transport = DailyTransport(
|
||||||
|
room_url,
|
||||||
|
token,
|
||||||
|
"Respond bot",
|
||||||
|
DailyParams(
|
||||||
|
audio_out_enabled=True,
|
||||||
|
transcription_enabled=True,
|
||||||
|
vad_enabled=True,
|
||||||
|
vad_analyzer=SileroVADAnalyzer(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
tts = FishAudioTTSService(
|
||||||
|
api_key=os.getenv("FISH_API_KEY"),
|
||||||
|
model="4ce7e917cedd4bc2bb2e6ff3a46acaa1", # Barack Obama
|
||||||
|
)
|
||||||
|
|
||||||
|
llm = OpenAILLMService(api_key=os.getenv("OPENAI_API_KEY"), model="gpt-4o")
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. Your output will be converted to audio so don't include special characters in your answers. Respond to what the user said in a creative and helpful way.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = OpenAILLMContext(messages)
|
||||||
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
|
||||||
|
pipeline = Pipeline(
|
||||||
|
[
|
||||||
|
transport.input(), # Transport user input
|
||||||
|
context_aggregator.user(), # User responses
|
||||||
|
llm, # LLM
|
||||||
|
tts, # TTS
|
||||||
|
transport.output(), # Transport bot output
|
||||||
|
context_aggregator.assistant(), # Assistant spoken responses
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@transport.event_handler("on_first_participant_joined")
|
||||||
|
async def on_first_participant_joined(transport, participant):
|
||||||
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
|
# Kick off the conversation.
|
||||||
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
await runner.run(task)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
@@ -1,20 +1,19 @@
|
|||||||
from typing import Tuple
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from pipecat.processors.aggregators import SentenceAggregator
|
from typing import Tuple
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
|
||||||
|
|
||||||
from pipecat.transports.services.daily import DailyTransport
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
|
from pipecat.frames.frames import AudioFrame, EndFrame, ImageFrame, LLMMessagesFrame, TextFrame
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
|
from pipecat.processors.aggregators import SentenceAggregator
|
||||||
from pipecat.services.azure import AzureLLMService, AzureTTSService
|
from pipecat.services.azure import AzureLLMService, AzureTTSService
|
||||||
from pipecat.services.elevenlabs import ElevenLabsTTSService
|
from pipecat.services.elevenlabs import ElevenLabsTTSService
|
||||||
from pipecat.services.fal import FalImageGenService
|
from pipecat.services.fal import FalImageGenService
|
||||||
from pipecat.frames.frames import AudioFrame, EndFrame, ImageFrame, LLMMessagesFrame, TextFrame
|
from pipecat.transports.services.daily import DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
Frame,
|
Frame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
@@ -19,13 +23,7 @@ from pipecat.pipeline.pipeline import Pipeline
|
|||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from pipecat.pipeline.task import PipelineTask
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.transports.services.daily import DailyTransport, DailyParams
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
@@ -35,6 +33,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
class MirrorProcessor(FrameProcessor):
|
class MirrorProcessor(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, InputAudioRawFrame):
|
if isinstance(frame, InputAudioRawFrame):
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
OutputAudioRawFrame(
|
OutputAudioRawFrame(
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
Frame,
|
Frame,
|
||||||
InputAudioRawFrame,
|
InputAudioRawFrame,
|
||||||
@@ -25,12 +28,6 @@ from pipecat.transports.base_transport import TransportParams
|
|||||||
from pipecat.transports.local.tk import TkLocalTransport
|
from pipecat.transports.local.tk import TkLocalTransport
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -39,6 +36,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
class MirrorProcessor(FrameProcessor):
|
class MirrorProcessor(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, InputAudioRawFrame):
|
if isinstance(frame, InputAudioRawFrame):
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
OutputAudioRawFrame(
|
OutputAudioRawFrame(
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -19,12 +23,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import wave
|
import wave
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
Frame,
|
Frame,
|
||||||
@@ -29,12 +33,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -60,6 +58,8 @@ for file in sound_files:
|
|||||||
|
|
||||||
class OutboundSoundEffectWrapper(FrameProcessor):
|
class OutboundSoundEffectWrapper(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, LLMFullResponseEndFrame):
|
if isinstance(frame, LLMFullResponseEndFrame):
|
||||||
await self.push_frame(sounds["ding1.wav"])
|
await self.push_frame(sounds["ding1.wav"])
|
||||||
# In case anything else downstream needs it
|
# In case anything else downstream needs it
|
||||||
@@ -70,6 +70,8 @@ class OutboundSoundEffectWrapper(FrameProcessor):
|
|||||||
|
|
||||||
class InboundSoundEffectWrapper(FrameProcessor):
|
class InboundSoundEffectWrapper(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, OpenAILLMContextFrame):
|
if isinstance(frame, OpenAILLMContextFrame):
|
||||||
await self.push_frame(sounds["ding2.wav"])
|
await self.push_frame(sounds["ding2.wav"])
|
||||||
# In case anything else downstream needs it
|
# In case anything else downstream needs it
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
|
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
@@ -21,12 +25,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.moondream import MoondreamService
|
from pipecat.services.moondream import MoondreamService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -42,6 +40,8 @@ class UserImageRequester(FrameProcessor):
|
|||||||
self._participant_id = participant_id
|
self._participant_id = participant_id
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if self._participant_id and isinstance(frame, TextFrame):
|
if self._participant_id and isinstance(frame, TextFrame):
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
UserImageRequestFrame(self._participant_id), FrameDirection.UPSTREAM
|
UserImageRequestFrame(self._participant_id), FrameDirection.UPSTREAM
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
|
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
@@ -21,12 +25,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.google import GoogleLLMService
|
from pipecat.services.google import GoogleLLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -42,6 +40,8 @@ class UserImageRequester(FrameProcessor):
|
|||||||
self._participant_id = participant_id
|
self._participant_id = participant_id
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if self._participant_id and isinstance(frame, TextFrame):
|
if self._participant_id and isinstance(frame, TextFrame):
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
UserImageRequestFrame(self._participant_id), FrameDirection.UPSTREAM
|
UserImageRequestFrame(self._participant_id), FrameDirection.UPSTREAM
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
|
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
@@ -21,12 +25,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -42,6 +40,8 @@ class UserImageRequester(FrameProcessor):
|
|||||||
self._participant_id = participant_id
|
self._participant_id = participant_id
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if self._participant_id and isinstance(frame, TextFrame):
|
if self._participant_id and isinstance(frame, TextFrame):
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
UserImageRequestFrame(self._participant_id), FrameDirection.UPSTREAM
|
UserImageRequestFrame(self._participant_id), FrameDirection.UPSTREAM
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
|
from pipecat.frames.frames import Frame, TextFrame, UserImageRequestFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
@@ -17,16 +21,10 @@ from pipecat.pipeline.task import PipelineTask
|
|||||||
from pipecat.processors.aggregators.user_response import UserResponseAggregator
|
from pipecat.processors.aggregators.user_response import UserResponseAggregator
|
||||||
from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator
|
from pipecat.processors.aggregators.vision_image_frame import VisionImageFrameAggregator
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
|
||||||
from pipecat.services.anthropic import AnthropicLLMService
|
from pipecat.services.anthropic import AnthropicLLMService
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -42,6 +40,8 @@ class UserImageRequester(FrameProcessor):
|
|||||||
self._participant_id = participant_id
|
self._participant_id = participant_id
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if self._participant_id and isinstance(frame, TextFrame):
|
if self._participant_id and isinstance(frame, TextFrame):
|
||||||
await self.push_frame(
|
await self.push_frame(
|
||||||
UserImageRequestFrame(self._participant_id), FrameDirection.UPSTREAM
|
UserImageRequestFrame(self._participant_id), FrameDirection.UPSTREAM
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import Frame, TranscriptionFrame
|
from pipecat.frames.frames import Frame, TranscriptionFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -16,12 +20,6 @@ from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
|||||||
from pipecat.services.whisper import WhisperSTTService
|
from pipecat.services.whisper import WhisperSTTService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -30,6 +28,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
class TranscriptionLogger(FrameProcessor):
|
class TranscriptionLogger(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, TranscriptionFrame):
|
if isinstance(frame, TranscriptionFrame):
|
||||||
print(f"Transcription: {frame.text}")
|
print(f"Transcription: {frame.text}")
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -7,6 +7,9 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from pipecat.frames.frames import Frame, TranscriptionFrame
|
from pipecat.frames.frames import Frame, TranscriptionFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -16,10 +19,6 @@ from pipecat.services.whisper import WhisperSTTService
|
|||||||
from pipecat.transports.base_transport import TransportParams
|
from pipecat.transports.base_transport import TransportParams
|
||||||
from pipecat.transports.local.audio import LocalAudioTransport
|
from pipecat.transports.local.audio import LocalAudioTransport
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -28,6 +27,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
class TranscriptionLogger(FrameProcessor):
|
class TranscriptionLogger(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, TranscriptionFrame):
|
if isinstance(frame, TranscriptionFrame):
|
||||||
print(f"Transcription: {frame.text}")
|
print(f"Transcription: {frame.text}")
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,26 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.frames.frames import Frame, TranscriptionFrame
|
from pipecat.frames.frames import Frame, TranscriptionFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from pipecat.pipeline.task import PipelineTask
|
||||||
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.services.deepgram import DeepgramSTTService, LiveOptions, Language
|
from pipecat.services.deepgram import DeepgramSTTService, Language, LiveOptions
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -31,6 +29,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
class TranscriptionLogger(FrameProcessor):
|
class TranscriptionLogger(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, TranscriptionFrame):
|
if isinstance(frame, TranscriptionFrame):
|
||||||
print(f"Transcription: {frame.text}")
|
print(f"Transcription: {frame.text}")
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -29,6 +29,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
class TranscriptionLogger(FrameProcessor):
|
class TranscriptionLogger(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, TranscriptionFrame):
|
if isinstance(frame, TranscriptionFrame):
|
||||||
print(f"Transcription: {frame.text}")
|
print(f"Transcription: {frame.text}")
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -29,6 +29,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
class TranscriptionLogger(FrameProcessor):
|
class TranscriptionLogger(FrameProcessor):
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
if isinstance(frame, TranscriptionFrame):
|
if isinstance(frame, TranscriptionFrame):
|
||||||
print(f"Transcription: {frame.text}")
|
print(f"Transcription: {frame.text}")
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,21 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from openai.types.chat import ChatCompletionToolParam
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -17,14 +23,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMContext, OpenAILLMService
|
from pipecat.services.openai import OpenAILLMContext, OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from openai.types.chat import ChatCompletionToolParam
|
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -32,11 +30,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
|
|
||||||
async def start_fetch_weather(function_name, llm, context):
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
# note: we can't push a frame to the LLM here. the bot
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
# can interrupt itself and/or cause audio overlapping glitches.
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
# possible question for Aleix and Chad about what the right way
|
|
||||||
# to trigger speech is, now, with the new queues/async/sync refactors.
|
|
||||||
# await llm.push_frame(TextFrame("Let me check on that."))
|
|
||||||
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,29 +1,27 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
|
||||||
from pipecat.services.anthropic import AnthropicLLMService
|
from pipecat.services.anthropic import AnthropicLLMService
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,29 +1,27 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
|
||||||
from pipecat.services.anthropic import AnthropicLLMService
|
from pipecat.services.anthropic import AnthropicLLMService
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -15,6 +15,7 @@ from openai.types.chat import ChatCompletionToolParam
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from pipecat.pipeline.task import PipelineTask
|
||||||
@@ -30,11 +31,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
|
|
||||||
async def start_fetch_weather(function_name, llm, context):
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
# note: we can't push a frame to the LLM here. the bot
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
# can interrupt itself and/or cause audio overlapping glitches.
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
# possible question for Aleix and Chad about what the right way
|
|
||||||
# to trigger speech is, now, with the new queues/async/sync refactors.
|
|
||||||
# await llm.push_frame(TextFrame("Let me check on that."))
|
|
||||||
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from openai.types.chat import ChatCompletionToolParam
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -17,14 +22,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMContext, OpenAILLMService
|
from pipecat.services.openai import OpenAILLMContext, OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from openai.types.chat import ChatCompletionToolParam
|
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
@@ -18,12 +22,6 @@ from pipecat.services.google import GoogleLLMService
|
|||||||
from pipecat.services.openai import OpenAILLMContext
|
from pipecat.services.openai import OpenAILLMContext
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -15,6 +15,7 @@ from openai.types.chat import ChatCompletionToolParam
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -30,11 +31,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
|
|
||||||
async def start_fetch_weather(function_name, llm, context):
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
# note: we can't push a frame to the LLM here. the bot
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
# can interrupt itself and/or cause audio overlapping glitches.
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
# possible question for Aleix and Chad about what the right way
|
|
||||||
# to trigger speech is, now, with the new queues/async/sync refactors.
|
|
||||||
# await llm.push_frame(TextFrame("Let me check on that."))
|
|
||||||
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -15,6 +15,7 @@ from openai.types.chat import ChatCompletionToolParam
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -30,11 +31,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
|
|
||||||
async def start_fetch_weather(function_name, llm, context):
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
# note: we can't push a frame to the LLM here. the bot
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
# can interrupt itself and/or cause audio overlapping glitches.
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
# possible question for Aleix and Chad about what the right way
|
|
||||||
# to trigger speech is, now, with the new queues/async/sync refactors.
|
|
||||||
# await llm.push_frame(TextFrame("Let me check on that."))
|
|
||||||
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -15,6 +15,7 @@ from openai.types.chat import ChatCompletionToolParam
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -30,11 +31,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
|
|
||||||
async def start_fetch_weather(function_name, llm, context):
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
# note: we can't push a frame to the LLM here. the bot
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
# can interrupt itself and/or cause audio overlapping glitches.
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
# possible question for Aleix and Chad about what the right way
|
|
||||||
# to trigger speech is, now, with the new queues/async/sync refactors.
|
|
||||||
# await llm.push_frame(TextFrame("Let me check on that."))
|
|
||||||
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -15,6 +15,7 @@ from openai.types.chat import ChatCompletionToolParam
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -30,11 +31,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
|
|
||||||
async def start_fetch_weather(function_name, llm, context):
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
# note: we can't push a frame to the LLM here. the bot
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
# can interrupt itself and/or cause audio overlapping glitches.
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
# possible question for Aleix and Chad about what the right way
|
|
||||||
# to trigger speech is, now, with the new queues/async/sync refactors.
|
|
||||||
# await llm.push_frame(TextFrame("Let me check on that."))
|
|
||||||
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -15,6 +15,7 @@ from openai.types.chat import ChatCompletionToolParam
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -30,11 +31,8 @@ logger.add(sys.stderr, level="DEBUG")
|
|||||||
|
|
||||||
|
|
||||||
async def start_fetch_weather(function_name, llm, context):
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
# note: we can't push a frame to the LLM here. the bot
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
# can interrupt itself and/or cause audio overlapping glitches.
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
# possible question for Aleix and Chad about what the right way
|
|
||||||
# to trigger speech is, now, with the new queues/async/sync refactors.
|
|
||||||
# await llm.push_frame(TextFrame("Let me check on that."))
|
|
||||||
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
@@ -65,7 +63,7 @@ async def main():
|
|||||||
)
|
)
|
||||||
|
|
||||||
llm = NimLLMService(
|
llm = NimLLMService(
|
||||||
api_key=os.getenv("NVIDIA_API_KEY"), model="meta/llama-3.1-405b-instruct"
|
api_key=os.getenv("NVIDIA_API_KEY"), model="meta/llama-3.3-70b-instruct"
|
||||||
)
|
)
|
||||||
# Register a function_name of None to get all functions
|
# Register a function_name of None to get all functions
|
||||||
# sent to the same callback with an additional function_name parameter.
|
# sent to the same callback with an additional function_name parameter.
|
||||||
@@ -76,18 +74,18 @@ async def main():
|
|||||||
type="function",
|
type="function",
|
||||||
function={
|
function={
|
||||||
"name": "get_current_weather",
|
"name": "get_current_weather",
|
||||||
"description": "Get the current weather",
|
"description": "Returns the current weather at a location, if one is specified, and defaults to the user's location.",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"location": {
|
"location": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The city and state, e.g. San Francisco, CA",
|
"description": "The location to find the weather of, or if not provided, it's the default location.",
|
||||||
},
|
},
|
||||||
"format": {
|
"format": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["celsius", "fahrenheit"],
|
"enum": ["celsius", "fahrenheit"],
|
||||||
"description": "The temperature unit to use. Infer this from the users location.",
|
"description": "Whether to use SI or USCS units (celsius or fahrenheit).",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"required": ["location", "format"],
|
"required": ["location", "format"],
|
||||||
|
|||||||
146
examples/foundational/14k-function-calling-cerebras.py
Normal file
146
examples/foundational/14k-function-calling-cerebras.py
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024–2025, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from openai.types.chat import ChatCompletionToolParam
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
|
from pipecat.services.cerebras import CerebrasLLMService
|
||||||
|
from pipecat.services.openai import OpenAILLMContext
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
logger.remove(0)
|
||||||
|
logger.add(sys.stderr, level="DEBUG")
|
||||||
|
|
||||||
|
|
||||||
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
|
||||||
|
await result_callback({"conditions": "nice", "temperature": "75"})
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
(room_url, token) = await configure(session)
|
||||||
|
|
||||||
|
transport = DailyTransport(
|
||||||
|
room_url,
|
||||||
|
token,
|
||||||
|
"Respond bot",
|
||||||
|
DailyParams(
|
||||||
|
audio_out_enabled=True,
|
||||||
|
transcription_enabled=True,
|
||||||
|
vad_enabled=True,
|
||||||
|
vad_analyzer=SileroVADAnalyzer(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
tts = CartesiaTTSService(
|
||||||
|
api_key=os.getenv("CARTESIA_API_KEY"),
|
||||||
|
voice_id="79a125e8-cd45-4c13-8a67-188112f4dd22", # British Lady
|
||||||
|
)
|
||||||
|
|
||||||
|
llm = CerebrasLLMService(api_key=os.getenv("CEREBRAS_API_KEY"), model="llama-3.3-70b")
|
||||||
|
# Register a function_name of None to get all functions
|
||||||
|
# sent to the same callback with an additional function_name parameter.
|
||||||
|
llm.register_function(None, fetch_weather_from_api, start_callback=start_fetch_weather)
|
||||||
|
|
||||||
|
tools = [
|
||||||
|
ChatCompletionToolParam(
|
||||||
|
type="function",
|
||||||
|
function={
|
||||||
|
"name": "get_current_weather",
|
||||||
|
"description": "Get the current weather for a specific location. You MUST use this function whenever asked about weather.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"location": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The city and state, e.g. San Francisco, CA",
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["celsius", "fahrenheit"],
|
||||||
|
"description": "The temperature unit to use. Use fahrenheit for US locations, celsius for others.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": ["location", "format"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
messages = [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": """You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way.
|
||||||
|
|
||||||
|
You have one functions available:
|
||||||
|
|
||||||
|
1. get_current_weather is used to get current weather information.
|
||||||
|
|
||||||
|
Infer whether to use Fahrenheit or Celsius automatically based on the location, unless the user specifies a preference.
|
||||||
|
|
||||||
|
Start by asking me for my location. Then, use 'get_weather_current' to give me a forecast.
|
||||||
|
|
||||||
|
Respond to what the user said in a creative and helpful way.""",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = OpenAILLMContext(messages, tools)
|
||||||
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
|
||||||
|
pipeline = Pipeline(
|
||||||
|
[
|
||||||
|
transport.input(),
|
||||||
|
context_aggregator.user(),
|
||||||
|
llm,
|
||||||
|
tts,
|
||||||
|
transport.output(),
|
||||||
|
context_aggregator.assistant(),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@transport.event_handler("on_first_participant_joined")
|
||||||
|
async def on_first_participant_joined(transport, participant):
|
||||||
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
|
# Kick off the conversation.
|
||||||
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
await runner.run(task)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
146
examples/foundational/14l-function-calling-deepseek.py
Normal file
146
examples/foundational/14l-function-calling-deepseek.py
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2025, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from openai.types.chat import ChatCompletionToolParam
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
|
from pipecat.services.deepseek import DeepSeekLLMService
|
||||||
|
from pipecat.services.openai import OpenAILLMContext
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
logger.remove(0)
|
||||||
|
logger.add(sys.stderr, level="DEBUG")
|
||||||
|
|
||||||
|
|
||||||
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
|
||||||
|
await result_callback({"conditions": "nice", "temperature": "75"})
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
(room_url, token) = await configure(session)
|
||||||
|
|
||||||
|
transport = DailyTransport(
|
||||||
|
room_url,
|
||||||
|
token,
|
||||||
|
"Respond bot",
|
||||||
|
DailyParams(
|
||||||
|
audio_out_enabled=True,
|
||||||
|
transcription_enabled=True,
|
||||||
|
vad_enabled=True,
|
||||||
|
vad_analyzer=SileroVADAnalyzer(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
tts = CartesiaTTSService(
|
||||||
|
api_key=os.getenv("CARTESIA_API_KEY"),
|
||||||
|
voice_id="79a125e8-cd45-4c13-8a67-188112f4dd22", # British Lady
|
||||||
|
)
|
||||||
|
|
||||||
|
llm = DeepSeekLLMService(api_key=os.getenv("DEEPSEEK_API_KEY"), model="deepseek-chat")
|
||||||
|
# Register a function_name of None to get all functions
|
||||||
|
# sent to the same callback with an additional function_name parameter.
|
||||||
|
llm.register_function(None, fetch_weather_from_api, start_callback=start_fetch_weather)
|
||||||
|
|
||||||
|
tools = [
|
||||||
|
ChatCompletionToolParam(
|
||||||
|
type="function",
|
||||||
|
function={
|
||||||
|
"name": "get_current_weather",
|
||||||
|
"description": "Get the current weather for a specific location. You MUST use this function whenever asked about weather.",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"location": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The city and state, e.g. San Francisco, CA",
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["celsius", "fahrenheit"],
|
||||||
|
"description": "The temperature unit to use. Use fahrenheit for US locations, celsius for others.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": ["location", "format"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
messages = [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": """You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way.
|
||||||
|
|
||||||
|
You have one functions available:
|
||||||
|
|
||||||
|
1. get_current_weather is used to get current weather information.
|
||||||
|
|
||||||
|
Infer whether to use Fahrenheit or Celsius automatically based on the location, unless the user specifies a preference.
|
||||||
|
|
||||||
|
Start by asking me for my location. Then, use 'get_weather_current' to give me a forecast.
|
||||||
|
|
||||||
|
Respond to what the user said in a creative and helpful way.""",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = OpenAILLMContext(messages, tools)
|
||||||
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
|
||||||
|
pipeline = Pipeline(
|
||||||
|
[
|
||||||
|
transport.input(),
|
||||||
|
context_aggregator.user(),
|
||||||
|
llm,
|
||||||
|
tts,
|
||||||
|
transport.output(),
|
||||||
|
context_aggregator.assistant(),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@transport.event_handler("on_first_participant_joined")
|
||||||
|
async def on_first_participant_joined(transport, participant):
|
||||||
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
|
# Kick off the conversation.
|
||||||
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
await runner.run(task)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
140
examples/foundational/14m-function-calling-openrouter.py
Normal file
140
examples/foundational/14m-function-calling-openrouter.py
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2024–2025, Daily
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
|
#
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from openai.types.chat import ChatCompletionToolParam
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import TTSSpeakFrame
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
|
from pipecat.services.azure import AzureTTSService
|
||||||
|
from pipecat.services.openrouter import OpenRouterLLMService
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
logger.remove(0)
|
||||||
|
logger.add(sys.stderr, level="DEBUG")
|
||||||
|
|
||||||
|
|
||||||
|
async def start_fetch_weather(function_name, llm, context):
|
||||||
|
"""Push a frame to the LLM; this is handy when the LLM response might take a while."""
|
||||||
|
await llm.push_frame(TTSSpeakFrame("Let me check on that."))
|
||||||
|
logger.debug(f"Starting fetch_weather_from_api with function_name: {function_name}")
|
||||||
|
|
||||||
|
|
||||||
|
async def fetch_weather_from_api(function_name, tool_call_id, args, llm, context, result_callback):
|
||||||
|
await result_callback({"conditions": "nice", "temperature": "75"})
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
(room_url, token) = await configure(session)
|
||||||
|
|
||||||
|
transport = DailyTransport(
|
||||||
|
room_url,
|
||||||
|
token,
|
||||||
|
"Respond bot",
|
||||||
|
DailyParams(
|
||||||
|
audio_out_enabled=True,
|
||||||
|
transcription_enabled=True,
|
||||||
|
vad_enabled=True,
|
||||||
|
vad_analyzer=SileroVADAnalyzer(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
tts = AzureTTSService(
|
||||||
|
api_key=os.getenv("AZURE_API_KEY"),
|
||||||
|
region="eastus",
|
||||||
|
voice="en-US-JennyNeural",
|
||||||
|
params=AzureTTSService.InputParams(language="en-US", rate="1.1", style="cheerful"),
|
||||||
|
)
|
||||||
|
|
||||||
|
llm = OpenRouterLLMService(
|
||||||
|
api_key=os.getenv("OPENROUTER_API_KEY"), model="openai/gpt-4o-2024-11-20"
|
||||||
|
)
|
||||||
|
# Register a function_name of None to get all functions
|
||||||
|
# sent to the same callback with an additional function_name parameter.
|
||||||
|
llm.register_function(None, fetch_weather_from_api, start_callback=start_fetch_weather)
|
||||||
|
|
||||||
|
tools = [
|
||||||
|
ChatCompletionToolParam(
|
||||||
|
type="function",
|
||||||
|
function={
|
||||||
|
"name": "get_current_weather",
|
||||||
|
"description": "Get the current weather",
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"location": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The city and state, e.g. San Francisco, CA",
|
||||||
|
},
|
||||||
|
"format": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["celsius", "fahrenheit"],
|
||||||
|
"description": "The temperature unit to use. Infer this from the users location.",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"required": ["location", "format"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
]
|
||||||
|
messages = [
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "You are a helpful LLM in a WebRTC call. Your goal is to demonstrate your capabilities in a succinct way. Your output will be converted to audio so don't include special characters in your answers. Respond to what the user said in a creative and helpful way.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
context = OpenAILLMContext(messages, tools)
|
||||||
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
|
||||||
|
pipeline = Pipeline(
|
||||||
|
[
|
||||||
|
transport.input(),
|
||||||
|
context_aggregator.user(),
|
||||||
|
llm,
|
||||||
|
tts,
|
||||||
|
transport.output(),
|
||||||
|
context_aggregator.assistant(),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
task = PipelineTask(
|
||||||
|
pipeline,
|
||||||
|
PipelineParams(
|
||||||
|
allow_interruptions=True,
|
||||||
|
enable_metrics=True,
|
||||||
|
enable_usage_metrics=True,
|
||||||
|
report_only_initial_ttfb=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@transport.event_handler("on_first_participant_joined")
|
||||||
|
async def on_first_participant_joined(transport, participant):
|
||||||
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
|
# Kick off the conversation.
|
||||||
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
await runner.run(task)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
@@ -1,18 +1,22 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from openai.types.chat import ChatCompletionToolParam
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
|
||||||
from pipecat.pipeline.parallel_pipeline import ParallelPipeline
|
from pipecat.pipeline.parallel_pipeline import ParallelPipeline
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
@@ -21,14 +25,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from openai.types.chat import ChatCompletionToolParam
|
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -149,7 +145,7 @@ async def main():
|
|||||||
"content": f"Please introduce yourself to the user and let them know the voices you can do. Your initial responses should be as if you were a {current_voice}.",
|
"content": f"Please introduce yourself to the user and let them know the voices you can do. Your initial responses should be as if you were a {current_voice}.",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
from deepgram import LiveOptions
|
from deepgram import LiveOptions
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from openai.types.chat import ChatCompletionToolParam
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
|
||||||
from pipecat.pipeline.parallel_pipeline import ParallelPipeline
|
from pipecat.pipeline.parallel_pipeline import ParallelPipeline
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
@@ -24,14 +27,6 @@ from pipecat.services.deepgram import DeepgramSTTService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from openai.types.chat import ChatCompletionToolParam
|
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -143,7 +138,7 @@ async def main():
|
|||||||
"content": f"Please introduce yourself to the user and let them know the languages you speak. Your initial responses should be in {current_language}.",
|
"content": f"Please introduce yourself to the user and let them know the languages you speak. Your initial responses should be in {current_language}.",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -14,7 +14,6 @@ from loguru import logger
|
|||||||
from runner import configure
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -98,7 +97,7 @@ async def main():
|
|||||||
@transport.event_handler("on_first_participant_joined")
|
@transport.event_handler("on_first_participant_joined")
|
||||||
async def on_first_participant_joined(transport, participant):
|
async def on_first_participant_joined(transport, participant):
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
# Handle "latency-ping" messages. The client will send app messages that look like
|
# Handle "latency-ping" messages. The client will send app messages that look like
|
||||||
# this:
|
# this:
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
from pipecat.frames.frames import EndFrame, LLMMessagesFrame, TTSSpeakFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
@@ -20,12 +24,6 @@ from pipecat.services.cartesia import CartesiaTTSService
|
|||||||
from pipecat.services.openai import OpenAILLMService
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -65,16 +63,36 @@ async def main():
|
|||||||
context = OpenAILLMContext(messages)
|
context = OpenAILLMContext(messages)
|
||||||
context_aggregator = llm.create_context_aggregator(context)
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
|
||||||
async def user_idle_callback(user_idle: UserIdleProcessor):
|
async def handle_user_idle(user_idle: UserIdleProcessor, retry_count: int) -> bool:
|
||||||
|
if retry_count == 1:
|
||||||
|
# First attempt: Add a gentle prompt to the conversation
|
||||||
messages.append(
|
messages.append(
|
||||||
{
|
{
|
||||||
"role": "system",
|
"role": "system",
|
||||||
"content": "Ask the user if they are still there and try to prompt for some input, but be short.",
|
"content": "The user has been quiet. Politely and briefly ask if they're still there.",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
await user_idle.push_frame(LLMMessagesFrame(messages))
|
await user_idle.push_frame(LLMMessagesFrame(messages))
|
||||||
|
return True
|
||||||
|
elif retry_count == 2:
|
||||||
|
# Second attempt: More direct prompt
|
||||||
|
messages.append(
|
||||||
|
{
|
||||||
|
"role": "system",
|
||||||
|
"content": "The user is still inactive. Ask if they'd like to continue our conversation.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
await user_idle.push_frame(LLMMessagesFrame(messages))
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
# Third attempt: End the conversation
|
||||||
|
await user_idle.push_frame(
|
||||||
|
TTSSpeakFrame("It seems like you're busy right now. Have a nice day!")
|
||||||
|
)
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
return False
|
||||||
|
|
||||||
user_idle = UserIdleProcessor(callback=user_idle_callback, timeout=5.0)
|
user_idle = UserIdleProcessor(callback=handle_user_idle, timeout=5.0)
|
||||||
|
|
||||||
pipeline = Pipeline(
|
pipeline = Pipeline(
|
||||||
[
|
[
|
||||||
@@ -102,7 +120,7 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,24 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import aiohttp
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure_with_args
|
||||||
|
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from pipecat.pipeline.task import PipelineTask
|
||||||
from pipecat.processors.gstreamer.pipeline_source import GStreamerPipelineSource
|
from pipecat.processors.gstreamer.pipeline_source import GStreamerPipelineSource
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure_with_args
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,25 +1,23 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineTask
|
from pipecat.pipeline.task import PipelineTask
|
||||||
from pipecat.processors.gstreamer.pipeline_source import GStreamerPipelineSource
|
from pipecat.processors.gstreamer.pipeline_source import GStreamerPipelineSource
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -24,9 +24,8 @@ from pipecat.pipeline.task import PipelineParams, PipelineTask
|
|||||||
from pipecat.processors.aggregators.openai_llm_context import (
|
from pipecat.processors.aggregators.openai_llm_context import (
|
||||||
OpenAILLMContext,
|
OpenAILLMContext,
|
||||||
)
|
)
|
||||||
from pipecat.services.openai import OpenAILLMService
|
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -24,9 +24,8 @@ from pipecat.pipeline.task import PipelineParams, PipelineTask
|
|||||||
from pipecat.processors.aggregators.openai_llm_context import (
|
from pipecat.processors.aggregators.openai_llm_context import (
|
||||||
OpenAILLMContext,
|
OpenAILLMContext,
|
||||||
)
|
)
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
|
||||||
from pipecat.services.anthropic import AnthropicLLMService
|
from pipecat.services.anthropic import AnthropicLLMService
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
@@ -26,7 +26,6 @@ from pipecat.processors.aggregators.openai_llm_context import (
|
|||||||
)
|
)
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.services.google import GoogleLLMService
|
from pipecat.services.google import GoogleLLMService
|
||||||
|
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|||||||
@@ -1,34 +1,29 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from typing import Any, Mapping
|
from typing import Any, Mapping
|
||||||
|
|
||||||
from pipecat.frames.frames import LLMMessagesFrame
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
|
from pipecat.frames.frames import EndFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.llm_response import (
|
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContext
|
||||||
LLMAssistantResponseAggregator,
|
|
||||||
LLMUserResponseAggregator,
|
|
||||||
)
|
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
from pipecat.services.openai import OpenAILLMService
|
|
||||||
from pipecat.services.deepgram import DeepgramSTTService
|
from pipecat.services.deepgram import DeepgramSTTService
|
||||||
|
from pipecat.services.openai import OpenAILLMService
|
||||||
from pipecat.services.tavus import TavusVideoService
|
from pipecat.services.tavus import TavusVideoService
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
@@ -41,7 +36,6 @@ async def main():
|
|||||||
tavus = TavusVideoService(
|
tavus = TavusVideoService(
|
||||||
api_key=os.getenv("TAVUS_API_KEY"),
|
api_key=os.getenv("TAVUS_API_KEY"),
|
||||||
replica_id=os.getenv("TAVUS_REPLICA_ID"),
|
replica_id=os.getenv("TAVUS_REPLICA_ID"),
|
||||||
persona_id=os.getenv("TAVUS_PERSONA_ID", "pipecat0"),
|
|
||||||
session=session,
|
session=session,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -76,19 +70,19 @@ async def main():
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
tma_in = LLMUserResponseAggregator(messages)
|
context = OpenAILLMContext(messages)
|
||||||
tma_out = LLMAssistantResponseAggregator(messages)
|
context_aggregator = llm.create_context_aggregator(context)
|
||||||
|
|
||||||
pipeline = Pipeline(
|
pipeline = Pipeline(
|
||||||
[
|
[
|
||||||
transport.input(), # Transport user input
|
transport.input(), # Transport user input
|
||||||
stt, # STT
|
stt, # STT
|
||||||
tma_in, # User responses
|
context_aggregator.user(), # User responses
|
||||||
llm, # LLM
|
llm, # LLM
|
||||||
tts, # TTS
|
tts, # TTS
|
||||||
tavus, # Tavus output layer
|
tavus, # Tavus output layer
|
||||||
transport.output(), # Transport bot output
|
transport.output(), # Transport bot output
|
||||||
tma_out, # Assistant spoken responses
|
context_aggregator.assistant(), # Assistant spoken responses
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -122,7 +116,11 @@ async def main():
|
|||||||
messages.append(
|
messages.append(
|
||||||
{"role": "system", "content": "Please introduce yourself to the user."}
|
{"role": "system", "content": "Please introduce yourself to the user."}
|
||||||
)
|
)
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
|
@transport.event_handler("on_participant_left")
|
||||||
|
async def on_participant_left(transport, participant, reason):
|
||||||
|
await task.queue_frame(EndFrame())
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import aiohttp
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame, TextFrame
|
from pipecat.frames.frames import TextFrame
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
|
||||||
from pipecat.pipeline.parallel_pipeline import ParallelPipeline
|
from pipecat.pipeline.parallel_pipeline import ParallelPipeline
|
||||||
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
from pipecat.processors.aggregators.gated_openai_llm_context import GatedOpenAILLMContextAggregator
|
from pipecat.processors.aggregators.gated_openai_llm_context import GatedOpenAILLMContextAggregator
|
||||||
@@ -26,12 +30,6 @@ from pipecat.services.openai import OpenAILLMService
|
|||||||
from pipecat.sync.event_notifier import EventNotifier
|
from pipecat.sync.event_notifier import EventNotifier
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
|
|
||||||
from runner import configure
|
|
||||||
|
|
||||||
from loguru import logger
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
logger.remove(0)
|
logger.remove(0)
|
||||||
@@ -157,7 +155,7 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
runner = PipelineRunner()
|
runner = PipelineRunner()
|
||||||
|
|
||||||
|
|||||||
@@ -1,53 +1,51 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2024, Daily
|
# Copyright (c) 2024–2025, Daily
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: BSD 2-Clause License
|
# SPDX-License-Identifier: BSD 2-Clause License
|
||||||
#
|
#
|
||||||
|
|
||||||
import aiohttp
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
import aiohttp
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from loguru import logger
|
||||||
|
from runner import configure
|
||||||
|
|
||||||
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
from pipecat.audio.vad.silero import SileroVADAnalyzer
|
||||||
from pipecat.frames.frames import LLMMessagesFrame, TextFrame
|
|
||||||
from pipecat.pipeline.pipeline import Pipeline
|
|
||||||
from pipecat.pipeline.parallel_pipeline import ParallelPipeline
|
|
||||||
from pipecat.pipeline.runner import PipelineRunner
|
|
||||||
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
|
||||||
from pipecat.processors.aggregators.openai_llm_context import (
|
|
||||||
OpenAILLMContext,
|
|
||||||
)
|
|
||||||
from pipecat.services.cartesia import CartesiaTTSService
|
|
||||||
from pipecat.services.deepgram import DeepgramSTTService
|
|
||||||
from pipecat.services.openai import OpenAILLMService
|
|
||||||
from pipecat.sync.event_notifier import EventNotifier
|
|
||||||
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
|
||||||
from pipecat.processors.frame_processor import FrameProcessor, FrameDirection
|
|
||||||
from pipecat.frames.frames import (
|
from pipecat.frames.frames import (
|
||||||
CancelFrame,
|
CancelFrame,
|
||||||
EndFrame,
|
EndFrame,
|
||||||
Frame,
|
Frame,
|
||||||
|
LLMMessagesFrame,
|
||||||
StartFrame,
|
StartFrame,
|
||||||
StartInterruptionFrame,
|
StartInterruptionFrame,
|
||||||
StopInterruptionFrame,
|
StopInterruptionFrame,
|
||||||
SystemFrame,
|
SystemFrame,
|
||||||
|
TextFrame,
|
||||||
TranscriptionFrame,
|
TranscriptionFrame,
|
||||||
UserStartedSpeakingFrame,
|
UserStartedSpeakingFrame,
|
||||||
UserStoppedSpeakingFrame,
|
UserStoppedSpeakingFrame,
|
||||||
)
|
)
|
||||||
from pipecat.processors.aggregators.openai_llm_context import OpenAILLMContextFrame
|
from pipecat.pipeline.parallel_pipeline import ParallelPipeline
|
||||||
from pipecat.sync.base_notifier import BaseNotifier
|
from pipecat.pipeline.pipeline import Pipeline
|
||||||
|
from pipecat.pipeline.runner import PipelineRunner
|
||||||
|
from pipecat.pipeline.task import PipelineParams, PipelineTask
|
||||||
|
from pipecat.processors.aggregators.openai_llm_context import (
|
||||||
|
OpenAILLMContext,
|
||||||
|
OpenAILLMContextFrame,
|
||||||
|
)
|
||||||
from pipecat.processors.filters.function_filter import FunctionFilter
|
from pipecat.processors.filters.function_filter import FunctionFilter
|
||||||
|
from pipecat.processors.frame_processor import FrameDirection, FrameProcessor
|
||||||
from pipecat.processors.user_idle_processor import UserIdleProcessor
|
from pipecat.processors.user_idle_processor import UserIdleProcessor
|
||||||
|
from pipecat.services.cartesia import CartesiaTTSService
|
||||||
|
from pipecat.services.deepgram import DeepgramSTTService
|
||||||
from runner import configure
|
from pipecat.services.openai import OpenAILLMService
|
||||||
|
from pipecat.sync.base_notifier import BaseNotifier
|
||||||
from loguru import logger
|
from pipecat.sync.event_notifier import EventNotifier
|
||||||
|
from pipecat.transports.services.daily import DailyParams, DailyTransport
|
||||||
from dotenv import load_dotenv
|
|
||||||
|
|
||||||
load_dotenv(override=True)
|
load_dotenv(override=True)
|
||||||
|
|
||||||
@@ -64,6 +62,7 @@ class StatementJudgeContextFilter(FrameProcessor):
|
|||||||
self._notifier = notifier
|
self._notifier = notifier
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
# We must not block system frames.
|
# We must not block system frames.
|
||||||
if isinstance(frame, SystemFrame):
|
if isinstance(frame, SystemFrame):
|
||||||
await self.push_frame(frame, direction)
|
await self.push_frame(frame, direction)
|
||||||
@@ -117,6 +116,7 @@ class CompletenessCheck(FrameProcessor):
|
|||||||
self._notifier = notifier
|
self._notifier = notifier
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
if isinstance(frame, TextFrame) and frame.text == "YES":
|
if isinstance(frame, TextFrame) and frame.text == "YES":
|
||||||
logger.debug("Completeness check YES")
|
logger.debug("Completeness check YES")
|
||||||
await self.push_frame(UserStoppedSpeakingFrame())
|
await self.push_frame(UserStoppedSpeakingFrame())
|
||||||
@@ -139,6 +139,8 @@ class OutputGate(FrameProcessor):
|
|||||||
self._gate_open = True
|
self._gate_open = True
|
||||||
|
|
||||||
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
async def process_frame(self, frame: Frame, direction: FrameDirection):
|
||||||
|
await super().process_frame(frame, direction)
|
||||||
|
|
||||||
# We must not block system frames.
|
# We must not block system frames.
|
||||||
if isinstance(frame, SystemFrame):
|
if isinstance(frame, SystemFrame):
|
||||||
if isinstance(frame, StartFrame):
|
if isinstance(frame, StartFrame):
|
||||||
@@ -167,8 +169,7 @@ class OutputGate(FrameProcessor):
|
|||||||
self._gate_task = self.get_event_loop().create_task(self._gate_task_handler())
|
self._gate_task = self.get_event_loop().create_task(self._gate_task_handler())
|
||||||
|
|
||||||
async def _stop(self):
|
async def _stop(self):
|
||||||
self._gate_task.cancel()
|
await self.cancel_task(self._gate_task)
|
||||||
await self._gate_task
|
|
||||||
|
|
||||||
async def _gate_task_handler(self):
|
async def _gate_task_handler(self):
|
||||||
while True:
|
while True:
|
||||||
@@ -309,7 +310,7 @@ async def main():
|
|||||||
await transport.capture_participant_transcription(participant["id"])
|
await transport.capture_participant_transcription(participant["id"])
|
||||||
# Kick off the conversation.
|
# Kick off the conversation.
|
||||||
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
messages.append({"role": "system", "content": "Please introduce yourself to the user."})
|
||||||
await task.queue_frames([LLMMessagesFrame(messages)])
|
await task.queue_frames([context_aggregator.user().get_context_frame()])
|
||||||
|
|
||||||
@transport.event_handler("on_app_message")
|
@transport.event_handler("on_app_message")
|
||||||
async def on_app_message(transport, message, sender):
|
async def on_app_message(transport, message, sender):
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user