Add simplified pstn examples (#1822)

* Add simplified pstn examples
* Add daily_twilio_sip_dial_out example
This commit is contained in:
Dominic Stewart
2025-06-02 14:50:21 +09:00
committed by GitHub
parent 6d24514ace
commit 70951b1198
52 changed files with 3348 additions and 2324 deletions

View File

@@ -0,0 +1,121 @@
#
# Copyright (c) 20242025, Daily
#
# SPDX-License-Identifier: BSD 2-Clause License
#
"""server.py.
Webhook server to handle webhook coming from Daily, create a Daily room and start the bot.
"""
import json
import os
import shlex
import subprocess
from contextlib import asynccontextmanager
import aiohttp
import uvicorn
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from utils.daily_helpers import create_daily_room
load_dotenv()
# ----------------- API ----------------- #
@asynccontextmanager
async def lifespan(app: FastAPI):
# Create aiohttp session to be used for Daily API calls
app.state.session = aiohttp.ClientSession()
yield
# Close session when shutting down
await app.state.session.close()
app = FastAPI(lifespan=lifespan)
@app.post("/start")
async def handle_incoming_daily_webhook(request: Request) -> JSONResponse:
"""Handle dial-out request."""
print("Received webhook from Daily")
# Get the dial-in properties from the request
try:
data = await request.json()
if "test" in data:
# Pass through any webhook checks
return JSONResponse({"test": True})
if not data["dialout_settings"]:
raise HTTPException(
status_code=400, detail="Missing 'dialout_settings' in the request body"
)
if not data["dialout_settings"].get("phone_number"):
raise HTTPException(
status_code=400, detail="Missing 'phone_number' in dialout_settings"
)
# Extract the phone number we want to dial out to
caller_phone = str(data["dialout_settings"]["phone_number"])
print(f"Processing call to {caller_phone}")
# Create a Daily room with dial-in capabilities
try:
room_details = await create_daily_room(request.app.state.session, caller_phone)
except Exception as e:
print(f"Error creating Daily room: {e}")
raise HTTPException(status_code=500, detail=f"Failed to create Daily room: {str(e)}")
room_url = room_details["room_url"]
token = room_details["token"]
print(f"Created Daily room: {room_url} with token: {token}")
body_json = json.dumps(data)
bot_cmd = f"python3 -m bot -u {room_url} -t {token} -b {shlex.quote(body_json)}"
try:
# CHANGE: Keep stdout/stderr for debugging
# Start the bot in the background but capture output
subprocess.Popen(
bot_cmd,
shell=True,
# Don't redirect output so we can see logs
# stdout=subprocess.DEVNULL,
# stderr=subprocess.DEVNULL
)
print(f"Started bot process with command: {bot_cmd}")
except Exception as e:
print(f"Error starting bot: {e}")
raise HTTPException(status_code=500, detail=f"Failed to start bot: {str(e)}")
except HTTPException:
raise
except Exception as e:
print(f"Unexpected error: {str(e)}")
raise HTTPException(status_code=500, detail=f"Server error: {str(e)}")
# Grab a token for the user to join with
return JSONResponse({"room_url": room_url, "token": token})
@app.get("/health")
async def health_check():
"""Simple health check endpoint."""
return {"status": "healthy"}
# ----------------- Main ----------------- #
if __name__ == "__main__":
# Run the server
port = int(os.getenv("PORT", "7860"))
print(f"Starting server on port {port}")
uvicorn.run("server:app", host="0.0.0.0", port=port, reload=True)