diff --git a/examples/bot-ready-signalling/README.md b/examples/bot-ready-signalling/README.md
new file mode 100644
index 000000000..668b95124
--- /dev/null
+++ b/examples/bot-ready-signalling/README.md
@@ -0,0 +1,45 @@
+# Bot ready signaling
+
+A simple Pipecat example demonstrating how to handle signaling between the client and the bot,
+ensuring that the bot starts sending audio only when the client is available,
+thereby avoiding the risk of cutting off the beginning of the audio.
+
+## Quick Start
+
+### First, start the bot server:
+
+1. Navigate to the server directory:
+ ```bash
+ cd server
+ ```
+2. Create and activate a virtual environment:
+ ```bash
+ python3 -m venv venv
+ source venv/bin/activate # On Windows: venv\Scripts\activate
+ ```
+3. Install requirements:
+ ```bash
+ pip install -r requirements.txt
+ ```
+4. Copy env.example to .env and configure:
+ - Add your API keys
+5. Start the server:
+ ```bash
+ python server.py
+ ```
+
+### Next, connect using the client app:
+
+For client-side setup, refer to the [JavaScript Guide](client/javascript/README.md).
+
+## Important Note
+
+Ensure the bot server is running before using any client implementations.
+
+## Requirements
+
+- Python 3.10+
+- Node.js 16+ (for JavaScript)
+- Daily API key
+- Cartesia API key
+- Modern web browser with WebRTC support
\ No newline at end of file
diff --git a/examples/bot-ready-signalling/client/javascript/README.md b/examples/bot-ready-signalling/client/javascript/README.md
new file mode 100644
index 000000000..3b0c7f96e
--- /dev/null
+++ b/examples/bot-ready-signalling/client/javascript/README.md
@@ -0,0 +1,27 @@
+# JavaScript Implementation
+
+Basic implementation using the [Pipecat JavaScript SDK](https://docs.pipecat.ai/client/js/introduction).
+
+## Setup
+
+1. Run the bot server. See the [server README](../../README).
+
+2. Navigate to the `client/javascript` directory:
+
+```bash
+cd client/javascript
+```
+
+3. Install dependencies:
+
+```bash
+npm install
+```
+
+4. Run the client app:
+
+```
+npm run dev
+```
+
+5. Visit http://localhost:5173 in your browser.
diff --git a/examples/bot-ready-signalling/client/javascript/index.html b/examples/bot-ready-signalling/client/javascript/index.html
new file mode 100644
index 000000000..71dfe4597
--- /dev/null
+++ b/examples/bot-ready-signalling/client/javascript/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+ AI Chatbot
+
+
+
+
+
+
+ Status: Disconnected
+
+
+ Connect
+ Disconnect
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/bot-ready-signalling/client/javascript/package-lock.json b/examples/bot-ready-signalling/client/javascript/package-lock.json
new file mode 100644
index 000000000..f10bc8528
--- /dev/null
+++ b/examples/bot-ready-signalling/client/javascript/package-lock.json
@@ -0,0 +1,1082 @@
+{
+ "name": "client",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "client",
+ "version": "1.0.0",
+ "license": "ISC",
+ "dependencies": {
+ "@daily-co/daily-js": "0.74.0"
+ },
+ "devDependencies": {
+ "vite": "^6.0.2"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.26.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz",
+ "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==",
+ "license": "MIT",
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@daily-co/daily-js": {
+ "version": "0.74.0",
+ "resolved": "https://registry.npmjs.org/@daily-co/daily-js/-/daily-js-0.74.0.tgz",
+ "integrity": "sha512-wyZzt+sH7yh5Cg3DQeoZ1Yen8+bbai0/Zq8JZzklqELrpjiFuu34e3qwjwt79cx7T9eukbZbK6gtk3cmCBW3iw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "@sentry/browser": "^8.33.1",
+ "bowser": "^2.8.1",
+ "dequal": "^2.0.3",
+ "events": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
+ "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
+ "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
+ "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
+ "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
+ "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
+ "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
+ "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
+ "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
+ "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
+ "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
+ "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
+ "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
+ "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
+ "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
+ "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
+ "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
+ "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
+ "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
+ "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
+ "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
+ "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
+ "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
+ "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
+ "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
+ "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz",
+ "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz",
+ "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz",
+ "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz",
+ "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz",
+ "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz",
+ "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz",
+ "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz",
+ "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz",
+ "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz",
+ "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz",
+ "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz",
+ "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz",
+ "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz",
+ "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz",
+ "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz",
+ "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz",
+ "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz",
+ "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz",
+ "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@sentry-internal/browser-utils": {
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.50.0.tgz",
+ "integrity": "sha512-hZm6ngWTEzZhaMHpLIKB4wWp0Od1MdCZdvR5FRdIThUMLa1P8rXeolovTRfOE81NE755EiwJHzj4O7rq3EjA+A==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/core": "8.50.0"
+ },
+ "engines": {
+ "node": ">=14.18"
+ }
+ },
+ "node_modules/@sentry-internal/feedback": {
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.50.0.tgz",
+ "integrity": "sha512-79WlvSJYCXL/D0PBC8AIT4JbyS44AE3h6lP05IESXMqzTZl3KeSqCx317rwJw1KaxzeFd/JQwkFq95jaKAcLhg==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/core": "8.50.0"
+ },
+ "engines": {
+ "node": ">=14.18"
+ }
+ },
+ "node_modules/@sentry-internal/replay": {
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.50.0.tgz",
+ "integrity": "sha512-mhRPujzO6n+mb6ZR+wQNkSpjqIqDriR0hZEvdzHQdyXu9zVdCHUJ3sINkzpT1XwiypQVCEfxB6Oh9y/NmcQfGg==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/browser-utils": "8.50.0",
+ "@sentry/core": "8.50.0"
+ },
+ "engines": {
+ "node": ">=14.18"
+ }
+ },
+ "node_modules/@sentry-internal/replay-canvas": {
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.50.0.tgz",
+ "integrity": "sha512-Hv1bBaPpe62xFPLpuaUxVBUHd/Ed9bnGndeqN4hueeEGDT9T6NyVokgm35O5xE9/op6Yodm/3NfUkEg8oE++Aw==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/replay": "8.50.0",
+ "@sentry/core": "8.50.0"
+ },
+ "engines": {
+ "node": ">=14.18"
+ }
+ },
+ "node_modules/@sentry/browser": {
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-8.50.0.tgz",
+ "integrity": "sha512-aGJSpuKiHVKkLvd1VklJSZ2oCsl4wcKUVxKIa8dhJC8KjDY0vREQCywrlWuS5KYP0xFy4k28pg6PPR3HKkUlNw==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/browser-utils": "8.50.0",
+ "@sentry-internal/feedback": "8.50.0",
+ "@sentry-internal/replay": "8.50.0",
+ "@sentry-internal/replay-canvas": "8.50.0",
+ "@sentry/core": "8.50.0"
+ },
+ "engines": {
+ "node": ">=14.18"
+ }
+ },
+ "node_modules/@sentry/core": {
+ "version": "8.50.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.50.0.tgz",
+ "integrity": "sha512-q71m8Ha9YGwqn4Gd7sWvcFTRgbHXxEfU4QeIFtwMBpwHfq2Q+9koiF8DOoOHqIEOsnlvZWRQgGggIOdHzajnVw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.18"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
+ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/bowser": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz",
+ "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==",
+ "license": "MIT"
+ },
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.24.2",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
+ "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.24.2",
+ "@esbuild/android-arm": "0.24.2",
+ "@esbuild/android-arm64": "0.24.2",
+ "@esbuild/android-x64": "0.24.2",
+ "@esbuild/darwin-arm64": "0.24.2",
+ "@esbuild/darwin-x64": "0.24.2",
+ "@esbuild/freebsd-arm64": "0.24.2",
+ "@esbuild/freebsd-x64": "0.24.2",
+ "@esbuild/linux-arm": "0.24.2",
+ "@esbuild/linux-arm64": "0.24.2",
+ "@esbuild/linux-ia32": "0.24.2",
+ "@esbuild/linux-loong64": "0.24.2",
+ "@esbuild/linux-mips64el": "0.24.2",
+ "@esbuild/linux-ppc64": "0.24.2",
+ "@esbuild/linux-riscv64": "0.24.2",
+ "@esbuild/linux-s390x": "0.24.2",
+ "@esbuild/linux-x64": "0.24.2",
+ "@esbuild/netbsd-arm64": "0.24.2",
+ "@esbuild/netbsd-x64": "0.24.2",
+ "@esbuild/openbsd-arm64": "0.24.2",
+ "@esbuild/openbsd-x64": "0.24.2",
+ "@esbuild/sunos-x64": "0.24.2",
+ "@esbuild/win32-arm64": "0.24.2",
+ "@esbuild/win32-ia32": "0.24.2",
+ "@esbuild/win32-x64": "0.24.2"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.8",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
+ "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/postcss": {
+ "version": "8.5.1",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
+ "integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.8",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
+ "license": "MIT"
+ },
+ "node_modules/rollup": {
+ "version": "4.30.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz",
+ "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.6"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.30.1",
+ "@rollup/rollup-android-arm64": "4.30.1",
+ "@rollup/rollup-darwin-arm64": "4.30.1",
+ "@rollup/rollup-darwin-x64": "4.30.1",
+ "@rollup/rollup-freebsd-arm64": "4.30.1",
+ "@rollup/rollup-freebsd-x64": "4.30.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.30.1",
+ "@rollup/rollup-linux-arm-musleabihf": "4.30.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.30.1",
+ "@rollup/rollup-linux-arm64-musl": "4.30.1",
+ "@rollup/rollup-linux-loongarch64-gnu": "4.30.1",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.30.1",
+ "@rollup/rollup-linux-s390x-gnu": "4.30.1",
+ "@rollup/rollup-linux-x64-gnu": "4.30.1",
+ "@rollup/rollup-linux-x64-musl": "4.30.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.30.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.30.1",
+ "@rollup/rollup-win32-x64-msvc": "4.30.1",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.0.7",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz",
+ "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.24.2",
+ "postcss": "^8.4.49",
+ "rollup": "^4.23.0"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ }
+ }
+}
diff --git a/examples/bot-ready-signalling/client/javascript/package.json b/examples/bot-ready-signalling/client/javascript/package.json
new file mode 100644
index 000000000..53b28499b
--- /dev/null
+++ b/examples/bot-ready-signalling/client/javascript/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "client",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "ISC",
+ "description": "",
+ "devDependencies": {
+ "vite": "^6.0.2"
+ },
+ "dependencies": {
+ "@daily-co/daily-js": "0.74.0"
+ }
+}
diff --git a/examples/bot-ready-signalling/client/javascript/src/app.js b/examples/bot-ready-signalling/client/javascript/src/app.js
new file mode 100644
index 000000000..5e0232f68
--- /dev/null
+++ b/examples/bot-ready-signalling/client/javascript/src/app.js
@@ -0,0 +1,216 @@
+/**
+ * Copyright (c) 2024–2025, Daily
+ *
+ * SPDX-License-Identifier: BSD 2-Clause License
+ */
+
+import Daily from "@daily-co/daily-js";
+
+/**
+ * ChatbotClient handles the connection and media management for a real-time
+ * voice interaction with an AI bot.
+ */
+class ChatbotClient {
+ constructor() {
+ // Initialize client state
+ this.dailyCallObject = null;
+ this.setupDOMElements();
+ this.setupEventListeners();
+ }
+
+ /**
+ * Set up references to DOM elements and create necessary media elements
+ */
+ setupDOMElements() {
+ // Get references to UI control elements
+ this.connectBtn = document.getElementById('connect-btn');
+ this.disconnectBtn = document.getElementById('disconnect-btn');
+ this.statusSpan = document.getElementById('connection-status');
+ this.debugLog = document.getElementById('debug-log');
+
+ // Create an audio element for bot's voice output
+ this.botAudio = document.createElement('audio');
+ this.botAudio.autoplay = true;
+ this.botAudio.playsInline = true;
+ document.body.appendChild(this.botAudio);
+ }
+
+ /**
+ * Set up event listeners for connect/disconnect buttons
+ */
+ setupEventListeners() {
+ this.connectBtn.addEventListener('click', () => this.connect());
+ this.disconnectBtn.addEventListener('click', () => this.disconnect());
+ }
+
+ /**
+ * Add a timestamped message to the debug log
+ */
+ log(message) {
+ const entry = document.createElement('div');
+ entry.textContent = `${new Date().toISOString()} - ${message}`;
+
+ // Add styling based on message type
+ if (message.startsWith('User: ')) {
+ entry.style.color = '#2196F3'; // blue for user
+ } else if (message.startsWith('Bot: ')) {
+ entry.style.color = '#4CAF50'; // green for bot
+ }
+
+ this.debugLog.appendChild(entry);
+ this.debugLog.scrollTop = this.debugLog.scrollHeight;
+ console.log(message);
+ }
+
+ /**
+ * Update the connection status display
+ */
+ updateStatus(status) {
+ this.statusSpan.textContent = status;
+ this.log(`Status: ${status}`);
+ }
+
+ handleEventToConsole (evt) {
+ this.log(`Received event: ${evt.action}`);
+ };
+
+ /**
+ * Set up listeners for track events (start/stop)
+ * This handles new tracks being added during the session
+ */
+ setupTrackListeners() {
+ if (!this.dailyCallObject) return;
+
+ this.dailyCallObject.on("joined-meeting", () => {
+ this.updateStatus('Connected');
+ this.connectBtn.disabled = true;
+ this.disconnectBtn.disabled = false;
+ this.log('Client connected');
+ });
+ this.dailyCallObject.on("track-started", (evt) => {
+ if (evt.track.kind === "audio" && evt.participant.local === false) {
+ this.log("Audio track started.")
+ this.setupAudioTrack(evt.track);
+ }
+ });
+ this.dailyCallObject.on("track-stopped", this.handleEventToConsole.bind(this));
+ this.dailyCallObject.on("participant-joined", this.handleEventToConsole.bind(this));
+ this.dailyCallObject.on("participant-updated", this.handleEventToConsole.bind(this));
+ this.dailyCallObject.on("participant-left", () => {
+ // When the bot leaves, we are also disconnecting from the call
+ this.disconnect()
+ });
+ this.dailyCallObject.on("left-meeting", () => {
+ this.updateStatus('Disconnected');
+ this.connectBtn.disabled = false;
+ this.disconnectBtn.disabled = true;
+ this.log('Client disconnected');
+ });
+ this.dailyCallObject.on("error", this.handleEventToConsole.bind(this));
+ }
+
+ /**
+ * Set up an audio track for playback
+ * Handles both initial setup and track updates
+ */
+ setupAudioTrack(track) {
+ this.log(`Setting up audio track, track state: ${track.readyState}, muted: ${track.muted}`);
+
+ // Check if we're already playing this track
+ if (this.botAudio.srcObject) {
+ const oldTrack = this.botAudio.srcObject.getAudioTracks()[0];
+ if (oldTrack?.id === track.id) return;
+ }
+ // Create a new MediaStream with the track and set it as the audio source
+ this.botAudio.srcObject = new MediaStream([track]);
+ this.botAudio.onplaying = async (event) => {
+ this.log("onplaying")
+ this.log("Will send the audio message to play the audio at the next tick")
+ this.dailyCallObject.sendAppMessage("playable")
+ }
+ }
+
+ async fetchRoomInfo() {
+ let connectUrl = '/connect'
+ let res = await fetch(connectUrl, {
+ method: "POST",
+ mode: "cors",
+ headers: new Headers({
+ "Content-Type": "application/json"
+ }),
+ })
+ if (res.ok) {
+ return res.json();
+ }
+ }
+
+ /**
+ * Initialize and connect to the bot
+ * This sets up the RTVI client, initializes devices, and establishes the connection
+ */
+ async connect() {
+ try {
+ // Initialize the client
+ this.dailyCallObject = Daily.createCallObject({
+ subscribeToTracksAutomatically: true,
+ });
+
+ // Set up listeners for media track events
+ this.setupTrackListeners();
+
+ this.log('Creating the bot...');
+ let roomInfo = await this.fetchRoomInfo()
+
+ // Connect to the bot
+ this.log('Connecting to bot...');
+ // Only for making debugger easier
+ window.callObject = this.dailyCallObject;
+ await this.dailyCallObject.join({
+ url: roomInfo.room_url,
+ });
+
+ this.log('Connection complete');
+ } catch (error) {
+ // Handle any errors during connection
+ this.log(`Error connecting: ${error.message}`);
+ this.log(`Error stack: ${error.stack}`);
+ this.updateStatus('Error');
+
+ // Clean up if there's an error
+ if (this.dailyCallObject) {
+ try {
+ await this.dailyCallObject.leave();
+ } catch (disconnectError) {
+ this.log(`Error during disconnect: ${disconnectError.message}`);
+ }
+ }
+ }
+ }
+
+ /**
+ * Disconnect from the bot and clean up media resources
+ */
+ async disconnect() {
+ if (this.dailyCallObject) {
+ try {
+ // Disconnect the RTVI client
+ await this.dailyCallObject.leave();
+ await this.dailyCallObject.destroy();
+ this.dailyCallObject = null;
+
+ // Clean up audio
+ if (this.botAudio.srcObject) {
+ this.botAudio.srcObject.getTracks().forEach((track) => track.stop());
+ this.botAudio.srcObject = null;
+ }
+ } catch (error) {
+ this.log(`Error disconnecting: ${error.message}`);
+ }
+ }
+ }
+}
+
+// Initialize the client when the page loads
+window.addEventListener('DOMContentLoaded', () => {
+ new ChatbotClient();
+});
diff --git a/examples/bot-ready-signalling/client/javascript/src/style.css b/examples/bot-ready-signalling/client/javascript/src/style.css
new file mode 100644
index 000000000..a3cb55776
--- /dev/null
+++ b/examples/bot-ready-signalling/client/javascript/src/style.css
@@ -0,0 +1,98 @@
+body {
+ margin: 0;
+ padding: 20px;
+ font-family: Arial, sans-serif;
+ background-color: #f0f0f0;
+}
+
+.container {
+ max-width: 1200px;
+ margin: 0 auto;
+}
+
+.status-bar {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px;
+ background-color: #fff;
+ border-radius: 8px;
+ margin-bottom: 20px;
+}
+
+.controls button {
+ padding: 8px 16px;
+ margin-left: 10px;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+}
+
+#connect-btn {
+ background-color: #4caf50;
+ color: white;
+}
+
+#disconnect-btn {
+ background-color: #f44336;
+ color: white;
+}
+
+button:disabled {
+ opacity: 0.5;
+ cursor: not-allowed;
+}
+
+.main-content {
+ background-color: #fff;
+ border-radius: 8px;
+ padding: 20px;
+ margin-bottom: 20px;
+}
+
+.bot-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+#bot-video-container {
+ width: 640px;
+ height: 360px;
+ background-color: #e0e0e0;
+ border-radius: 8px;
+ margin: 20px auto;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+#bot-video-container video {
+ width: 100%;
+ height: 100%;
+ object-fit: cover;
+}
+
+.debug-panel {
+ background-color: #fff;
+ border-radius: 8px;
+ padding: 20px;
+}
+
+.debug-panel h3 {
+ margin: 0 0 10px 0;
+ font-size: 16px;
+ font-weight: bold;
+}
+
+#debug-log {
+ height: 200px;
+ overflow-y: auto;
+ background-color: #f8f8f8;
+ padding: 10px;
+ border-radius: 4px;
+ font-family: monospace;
+ font-size: 12px;
+ line-height: 1.4;
+}
diff --git a/examples/bot-ready-signalling/client/javascript/vite.config.js b/examples/bot-ready-signalling/client/javascript/vite.config.js
new file mode 100644
index 000000000..5ccad4a6b
--- /dev/null
+++ b/examples/bot-ready-signalling/client/javascript/vite.config.js
@@ -0,0 +1,13 @@
+import { defineConfig } from 'vite';
+
+export default defineConfig({
+ server: {
+ proxy: {
+ // Proxy /api requests to the backend server
+ '/connect': {
+ target: 'http://0.0.0.0:7860', // Replace with your backend URL
+ changeOrigin: true,
+ },
+ },
+ },
+});
diff --git a/examples/bot-ready-signalling/server/README.md b/examples/bot-ready-signalling/server/README.md
new file mode 100644
index 000000000..4c72adb44
--- /dev/null
+++ b/examples/bot-ready-signalling/server/README.md
@@ -0,0 +1,50 @@
+# Bot ready signaling Server
+
+A FastAPI server that manages bot instances and provide endpoint for Pipecat client connections.
+
+## Endpoints
+
+- `POST /connect` - Pipecat client connection endpoint
+
+## Environment Variables
+
+Copy `env.example` to `.env` and configure:
+
+```ini
+# Required API Keys
+DAILY_API_KEY= # Your Daily API key
+CARTESIA_API_KEY= # Your Cartesia API key
+
+# Optional Configuration
+DAILY_API_URL= # Optional: Daily API URL (defaults to https://api.daily.co/v1)
+DAILY_SAMPLE_ROOM_URL= # Optional: Fixed room URL for development
+HOST= # Optional: Host address (defaults to 0.0.0.0)
+FAST_API_PORT= # Optional: Port number (defaults to 7860)
+```
+
+## Running the Server
+
+Set up and activate your virtual environment:
+
+```bash
+python3 -m venv venv
+source venv/bin/activate # On Windows: venv\Scripts\activate
+```
+
+Install dependencies:
+
+```bash
+pip install -r requirements.txt
+```
+
+If you want to use the local version of `pipecat` in this repo rather than the last published version, also run:
+
+```bash
+pip install --editable "../../../[daily,cartesia,openai]"
+```
+
+Run the server:
+
+```bash
+python server.py
+```
diff --git a/examples/bot-ready-signalling/server/env.example b/examples/bot-ready-signalling/server/env.example
new file mode 100644
index 000000000..43f083495
--- /dev/null
+++ b/examples/bot-ready-signalling/server/env.example
@@ -0,0 +1,3 @@
+DAILY_SAMPLE_ROOM_URL=https://yourdomain.daily.co/yourroom # (for joining the bot to the same room repeatedly for local dev)
+DAILY_API_KEY=
+CARTESIA_API_KEY=
\ No newline at end of file
diff --git a/examples/bot-ready-signalling/server/requirements.txt b/examples/bot-ready-signalling/server/requirements.txt
new file mode 100644
index 000000000..7b7cb164b
--- /dev/null
+++ b/examples/bot-ready-signalling/server/requirements.txt
@@ -0,0 +1,4 @@
+python-dotenv
+fastapi[all]
+uvicorn
+pipecat-ai[daily,cartesia,openai]
diff --git a/examples/bot-ready-signalling/server/runner.py b/examples/bot-ready-signalling/server/runner.py
new file mode 100644
index 000000000..c1556e8a4
--- /dev/null
+++ b/examples/bot-ready-signalling/server/runner.py
@@ -0,0 +1,63 @@
+#
+# Copyright (c) 2024–2025, Daily
+#
+# SPDX-License-Identifier: BSD 2-Clause License
+#
+
+import argparse
+import os
+
+import aiohttp
+
+from pipecat.transports.services.helpers.daily_rest import DailyRESTHelper
+
+
+async def configure(aiohttp_session: aiohttp.ClientSession):
+ (url, token, _) = await configure_with_args(aiohttp_session)
+ return (url, token)
+
+
+async def configure_with_args(
+ aiohttp_session: aiohttp.ClientSession, parser: argparse.ArgumentParser | None = None
+):
+ if not parser:
+ parser = argparse.ArgumentParser(description="Daily AI SDK Bot Sample")
+ parser.add_argument(
+ "-u", "--url", type=str, required=False, help="URL of the Daily room to join"
+ )
+ parser.add_argument(
+ "-k",
+ "--apikey",
+ type=str,
+ required=False,
+ help="Daily API Key (needed to create an owner token for the room)",
+ )
+
+ args, unknown = parser.parse_known_args()
+
+ url = args.url or os.getenv("DAILY_SAMPLE_ROOM_URL")
+ key = args.apikey or os.getenv("DAILY_API_KEY")
+
+ if not url:
+ raise Exception(
+ "No Daily room specified. use the -u/--url option from the command line, or set DAILY_SAMPLE_ROOM_URL in your environment to specify a Daily room URL."
+ )
+
+ if not key:
+ raise Exception(
+ "No Daily API key specified. use the -k/--apikey option from the command line, or set DAILY_API_KEY in your environment to specify a Daily API key, available from https://dashboard.daily.co/developers."
+ )
+
+ daily_rest_helper = DailyRESTHelper(
+ daily_api_key=key,
+ daily_api_url=os.getenv("DAILY_API_URL", "https://api.daily.co/v1"),
+ aiohttp_session=aiohttp_session,
+ )
+
+ # Create a meeting token for the given room with an expiration 1 hour in
+ # the future.
+ expiry_time: float = 60 * 60
+
+ token = await daily_rest_helper.get_token(url, expiry_time)
+
+ return (url, token, args)
diff --git a/examples/bot-ready-signalling/server/server.py b/examples/bot-ready-signalling/server/server.py
new file mode 100644
index 000000000..ca42aa0fc
--- /dev/null
+++ b/examples/bot-ready-signalling/server/server.py
@@ -0,0 +1,147 @@
+#
+# Copyright (c) 2025, Daily
+#
+# SPDX-License-Identifier: BSD 2-Clause License
+#
+
+import argparse
+import os
+import subprocess
+from contextlib import asynccontextmanager
+from typing import Any, Dict
+
+import aiohttp
+from dotenv import load_dotenv
+from fastapi import FastAPI, HTTPException, Request
+from fastapi.middleware.cors import CORSMiddleware
+from fastapi.responses import JSONResponse
+
+from pipecat.transports.services.helpers.daily_rest import DailyRESTHelper, DailyRoomParams
+
+# Load environment variables from .env file
+load_dotenv(override=True)
+
+# Dictionary to track bot processes: {pid: (process, room_url)}
+bot_procs = {}
+
+# Store Daily API helpers
+daily_helpers = {}
+
+
+def cleanup():
+ """Cleanup function to terminate all bot processes.
+
+ Called during server shutdown.
+ """
+ for entry in bot_procs.values():
+ proc = entry[0]
+ proc.terminate()
+ proc.wait()
+
+
+@asynccontextmanager
+async def lifespan(app: FastAPI):
+ """FastAPI lifespan manager that handles startup and shutdown tasks.
+
+ - Creates aiohttp session
+ - Initializes Daily API helper
+ - Cleans up resources on shutdown
+ """
+ aiohttp_session = aiohttp.ClientSession()
+ daily_helpers["rest"] = DailyRESTHelper(
+ daily_api_key=os.getenv("DAILY_API_KEY", ""),
+ daily_api_url=os.getenv("DAILY_API_URL", "https://api.daily.co/v1"),
+ aiohttp_session=aiohttp_session,
+ )
+ yield
+ await aiohttp_session.close()
+ cleanup()
+
+
+# Initialize FastAPI app with lifespan manager
+app = FastAPI(lifespan=lifespan)
+
+# Configure CORS to allow requests from any origin
+app.add_middleware(
+ CORSMiddleware,
+ allow_origins=["*"],
+ allow_credentials=True,
+ allow_methods=["*"],
+ allow_headers=["*"],
+)
+
+
+async def create_room_and_token() -> tuple[str, str]:
+ """Helper function to create a Daily room and generate an access token.
+
+ Returns:
+ tuple[str, str]: A tuple containing (room_url, token)
+
+ Raises:
+ HTTPException: If room creation or token generation fails
+ """
+ room = await daily_helpers["rest"].create_room(DailyRoomParams())
+ if not room.url:
+ raise HTTPException(status_code=500, detail="Failed to create room")
+
+ token = await daily_helpers["rest"].get_token(room.url)
+ if not token:
+ raise HTTPException(status_code=500, detail=f"Failed to get token for room: {room.url}")
+
+ return room.url, token
+
+
+@app.post("/connect")
+async def bot_connect(request: Request) -> Dict[Any, Any]:
+ """Connect endpoint that creates a room and returns connection credentials.
+
+ This endpoint is called by client to establish a connection.
+
+ Returns:
+ Dict[Any, Any]: Authentication bundle containing room_url and token
+
+ Raises:
+ HTTPException: If room creation, token generation, or bot startup fails
+ """
+ print("Creating room for RTVI connection")
+ room_url, token = await create_room_and_token()
+ print(f"Room URL: {room_url}")
+
+ # Start the bot process
+ try:
+ bot_file = "signalling_bot"
+ proc = subprocess.Popen(
+ [f"python3 -m {bot_file} -u {room_url} -t {token}"],
+ shell=True,
+ bufsize=1,
+ cwd=os.path.dirname(os.path.abspath(__file__)),
+ )
+ bot_procs[proc.pid] = (proc, room_url)
+ except Exception as e:
+ raise HTTPException(status_code=500, detail=f"Failed to start subprocess: {e}")
+
+ # Return the authentication bundle in format expected by DailyTransport
+ return {"room_url": room_url, "token": token}
+
+
+if __name__ == "__main__":
+ import uvicorn
+
+ # Parse command line arguments for server configuration
+ default_host = os.getenv("HOST", "0.0.0.0")
+ default_port = int(os.getenv("FAST_API_PORT", "7860"))
+
+ parser = argparse.ArgumentParser(description="Daily Travel Companion FastAPI server")
+ parser.add_argument("--host", type=str, default=default_host, help="Host address")
+ parser.add_argument("--port", type=int, default=default_port, help="Port number")
+ parser.add_argument("--reload", action="store_true", help="Reload code on change")
+
+ config = parser.parse_args()
+
+ # Start the FastAPI server
+ uvicorn.run(
+ "server:app",
+ host=config.host,
+ port=config.port,
+ reload=config.reload,
+ )
diff --git a/examples/bot-ready-signalling/server/signalling_bot.py b/examples/bot-ready-signalling/server/signalling_bot.py
new file mode 100644
index 000000000..23d407c05
--- /dev/null
+++ b/examples/bot-ready-signalling/server/signalling_bot.py
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 2024–2025, Daily
+#
+# SPDX-License-Identifier: BSD 2-Clause License
+#
+
+import asyncio
+import os
+import sys
+from dataclasses import dataclass
+
+import aiohttp
+from dotenv import load_dotenv
+from loguru import logger
+from runner import configure
+
+from pipecat.frames.frames import AudioRawFrame, EndFrame, OutputAudioRawFrame, TTSSpeakFrame
+from pipecat.pipeline.pipeline import Pipeline
+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)
+
+logger.remove(0)
+logger.add(sys.stderr, level="DEBUG")
+
+
+@dataclass
+class SilenceFrame(OutputAudioRawFrame):
+ def __init__(
+ self,
+ audio: bytes = None,
+ sample_rate: int = 16000,
+ num_channels: int = 1,
+ duration: float = 0.1,
+ ):
+ # Initialize the parent class with the silent frame's data
+ super().__init__(
+ audio=self.create_silent_audio_frame(sample_rate, num_channels, duration).audio,
+ sample_rate=sample_rate,
+ num_channels=num_channels,
+ )
+
+ @staticmethod
+ def create_silent_audio_frame(
+ sample_rate: int, num_channels: int, duration: float
+ ) -> AudioRawFrame:
+ """Create an AudioRawFrame containing silence."""
+ frame_size = num_channels * 2 # 2 bytes per sample for 16-bit audio
+ total_frames = int(sample_rate * duration)
+ total_bytes = total_frames * frame_size
+ silent_audio = bytes(total_bytes) # Create a byte array filled with zeros
+ return AudioRawFrame(audio=silent_audio, sample_rate=sample_rate, num_channels=num_channels)
+
+
+async def main():
+ async with aiohttp.ClientSession() as session:
+ (room_url, _) = await configure(session)
+
+ transport = DailyTransport(
+ room_url, None, "Say One Thing", DailyParams(audio_out_enabled=True)
+ )
+
+ tts = CartesiaTTSService(
+ api_key=os.getenv("CARTESIA_API_KEY"),
+ voice_id="79a125e8-cd45-4c13-8a67-188112f4dd22", # British Lady
+ )
+
+ runner = PipelineRunner()
+
+ task = PipelineTask(Pipeline([tts, transport.output()]))
+
+ # Register an event handler so we can play the audio when we receive a specific message
+ @transport.event_handler("on_app_message")
+ async def on_app_message(transport, message, sender):
+ logger.debug(f"Received app message: {message} - {sender}")
+ if "playable" not in message:
+ return
+ await task.queue_frames(
+ [
+ SilenceFrame(duration=0.5),
+ TTSSpeakFrame(f"Hello there, how are you doing today ?"),
+ EndFrame(),
+ ]
+ )
+
+ await runner.run(task)
+
+
+if __name__ == "__main__":
+ asyncio.run(main())