Compare commits

...

1 Commits

Author SHA1 Message Date
Mark Backman
b9f770d889 Add body args support to development runner 2025-08-02 13:39:55 -04:00
2 changed files with 50 additions and 12 deletions

View File

@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Added the ability to pass `body` properties to the development runner using
the `--body`/`-b` command. The `body` accepts an object provided using valid
JSON format. Currently, the `body` is only accepted when using
`DailyTransport`.
### Fixed
- Fixed an issue in `LiveKitTransport` where empty `AudioRawFrame`s were pushed

View File

@@ -61,6 +61,7 @@ To run locally:
- ESP32: `python bot.py -t webrtc --esp32 --host 192.168.1.100`
- Daily (server): `python bot.py -t daily`
- Daily (direct, testing only): `python bot.py -d`
- Daily with body data: `python bot.py -d --body '{"foo": "bar"}'`
- Telephony: `python bot.py -t twilio -x your_username.ngrok.io`
"""
@@ -150,7 +151,11 @@ async def _run_telephony_bot(websocket: WebSocket):
def _create_server_app(
transport_type: str, host: str = "localhost", proxy: str = None, esp32_mode: bool = False
transport_type: str,
host: str = "localhost",
proxy: str = None,
esp32_mode: bool = False,
body: dict = None,
):
"""Create FastAPI app with transport-specific routes."""
app = FastAPI()
@@ -167,7 +172,7 @@ def _create_server_app(
if transport_type == "webrtc":
_setup_webrtc_routes(app, esp32_mode=esp32_mode, host=host)
elif transport_type == "daily":
_setup_daily_routes(app)
_setup_daily_routes(app, body)
elif transport_type in ["twilio", "telnyx", "plivo"]:
_setup_telephony_routes(app, transport_type, proxy)
else:
@@ -246,7 +251,7 @@ def _setup_webrtc_routes(app: FastAPI, esp32_mode: bool = False, host: str = "lo
app.router.lifespan_context = lifespan
def _setup_daily_routes(app: FastAPI):
def _setup_daily_routes(app: FastAPI, body: dict = None):
"""Set up Daily-specific routes."""
@app.get("/")
@@ -261,9 +266,9 @@ def _setup_daily_routes(app: FastAPI):
async with aiohttp.ClientSession() as session:
room_url, token = await configure(session)
# Start the bot in the background
# Start the bot in the background with provided body
bot_module = _get_bot_module()
runner_args = DailyRunnerArguments(room_url=room_url, token=token, body={})
runner_args = DailyRunnerArguments(room_url=room_url, token=token, body=body or {})
asyncio.create_task(bot_module.bot(runner_args))
return RedirectResponse(room_url)
@@ -279,9 +284,9 @@ def _setup_daily_routes(app: FastAPI):
async with aiohttp.ClientSession() as session:
room_url, token = await configure(session)
# Start the bot in the background
# Start the bot in the background with provided body
bot_module = _get_bot_module()
runner_args = DailyRunnerArguments(room_url=room_url, token=token, body={})
runner_args = DailyRunnerArguments(room_url=room_url, token=token, body=body or {})
asyncio.create_task(bot_module.bot(runner_args))
return {"room_url": room_url, "token": token}
@@ -330,7 +335,7 @@ def _setup_telephony_routes(app: FastAPI, transport_type: str, proxy: str):
return {"status": f"Bot started with {transport_type}"}
async def _run_daily_direct():
async def _run_daily_direct(body: dict = None):
"""Run Daily bot with direct connection (no FastAPI server)."""
try:
import aiohttp
@@ -345,13 +350,16 @@ async def _run_daily_direct():
async with aiohttp.ClientSession() as session:
room_url, token = await configure(session)
runner_args = DailyRunnerArguments(room_url=room_url, token=token, body={})
# Use provided body or default to empty dict
runner_args = DailyRunnerArguments(room_url=room_url, token=token, body=body or {})
# Get the bot module and run it directly
bot_module = _get_bot_module()
print(f"📞 Joining Daily room: {room_url}")
print(" (Direct connection - no web server needed)")
if body:
print(f" Body data: {body}")
print()
await bot_module.bot(runner_args)
@@ -373,6 +381,7 @@ def main():
-x/--proxy: Public proxy hostname for telephony webhooks
--esp32: Enable SDP munging for ESP32 compatibility (requires --host with IP address)
-d/--direct: Connect directly to Daily room (automatically sets transport to daily)
-b/--body: JSON body data to pass to Daily bot (only valid with Daily transport)
-v/--verbose: Increase logging verbosity
The bot file must contain a `bot(runner_args)` function as the entry point.
@@ -402,6 +411,12 @@ def main():
default=False,
help="Connect directly to Daily room (automatically sets transport to daily)",
)
parser.add_argument(
"-b",
"--body",
type=str,
help="JSON body data to pass to Daily bot (only valid with Daily transport)",
)
parser.add_argument(
"--verbose", "-v", action="count", default=0, help="Increase logging verbosity"
)
@@ -415,6 +430,22 @@ def main():
logger.error("--direct flag only works with Daily transport (-t daily)")
return
# Validate body argument is only used with Daily transport
if args.body and args.transport != "daily":
logger.error("--body/-b flag only works with Daily transport (-t daily)")
return
# Parse and validate JSON body if provided
parsed_body = {}
if args.body:
try:
import json
parsed_body = json.loads(args.body)
except json.JSONDecodeError as e:
logger.error(f"Invalid JSON in --body argument: {e}")
return
# Validate ESP32 requirements
if args.esp32 and args.host == "localhost":
logger.error("For ESP32, you need to specify `--host IP` so we can do SDP munging.")
@@ -430,8 +461,8 @@ def main():
print("🚀 Connecting directly to Daily room...")
print()
# Run direct Daily connection
asyncio.run(_run_daily_direct())
# Run direct Daily connection with parsed body
asyncio.run(_run_daily_direct(parsed_body))
return
# Print startup message for server-based transports
@@ -452,7 +483,7 @@ def main():
print()
# Create the app with transport-specific setup
app = _create_server_app(args.transport, args.host, args.proxy, args.esp32)
app = _create_server_app(args.transport, args.host, args.proxy, args.esp32, parsed_body)
# Run the server
uvicorn.run(app, host=args.host, port=args.port)