mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-22 08:38:13 +02:00
80 lines
2.9 KiB
Python
80 lines
2.9 KiB
Python
"""Telnyx telephony routes (webhooks, status callbacks, answer URLs).
|
|
|
|
Mounted under ``/api/v1/telephony`` by ``api.routes.telephony`` via the
|
|
provider registry — see ProviderSpec.router.
|
|
"""
|
|
|
|
import json
|
|
|
|
from fastapi import APIRouter, Request
|
|
from loguru import logger
|
|
|
|
from api.db import db_client
|
|
from api.services.telephony.factory import get_telephony_provider
|
|
from api.services.telephony.providers.telnyx.provider import normalize_event_type
|
|
from api.services.telephony.status_processor import (
|
|
StatusCallbackRequest,
|
|
_process_status_update,
|
|
)
|
|
from pipecat.utils.run_context import set_current_run_id
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.post("/telnyx/events/{workflow_run_id}")
|
|
async def handle_telnyx_events(
|
|
request: Request,
|
|
workflow_run_id: int,
|
|
):
|
|
"""Handle Telnyx Call Control webhook events.
|
|
|
|
Telnyx sends all call lifecycle events (call.initiated, call.answered,
|
|
call.hangup, streaming.started, streaming.stopped) as JSON POST requests.
|
|
"""
|
|
set_current_run_id(workflow_run_id)
|
|
|
|
event_data = await request.json()
|
|
logger.info(
|
|
f"[run {workflow_run_id}] Received Telnyx event: {json.dumps(event_data)}"
|
|
)
|
|
|
|
# Extract event type from Telnyx envelope. Telnyx sometimes delivers the
|
|
# type with underscores (``streaming_started``) instead of dots
|
|
# (``streaming.started``); normalize so downstream comparisons match either.
|
|
data = event_data.get("data", {})
|
|
event_type = normalize_event_type(data.get("event_type", ""))
|
|
|
|
# Skip streaming events — they're informational only
|
|
if event_type in ("streaming.started", "streaming.stopped"):
|
|
logger.debug(f"[run {workflow_run_id}] Telnyx streaming event: {event_type}")
|
|
return {"status": "success"}
|
|
|
|
# Get workflow run and provider
|
|
workflow_run = await db_client.get_workflow_run_by_id(workflow_run_id)
|
|
if not workflow_run:
|
|
logger.warning(f"Workflow run {workflow_run_id} not found for Telnyx event")
|
|
return {"status": "ignored", "reason": "workflow_run_not_found"}
|
|
|
|
workflow = await db_client.get_workflow_by_id(workflow_run.workflow_id)
|
|
if not workflow:
|
|
logger.warning(f"Workflow {workflow_run.workflow_id} not found")
|
|
return {"status": "ignored", "reason": "workflow_not_found"}
|
|
|
|
provider = await get_telephony_provider(workflow.organization_id)
|
|
|
|
# Parse the callback data into generic format
|
|
parsed_data = provider.parse_status_callback(event_data)
|
|
|
|
status_update = StatusCallbackRequest(
|
|
call_id=parsed_data["call_id"],
|
|
status=parsed_data["status"],
|
|
from_number=parsed_data.get("from_number"),
|
|
to_number=parsed_data.get("to_number"),
|
|
direction=parsed_data.get("direction"),
|
|
duration=parsed_data.get("duration"),
|
|
extra=parsed_data.get("extra", {}),
|
|
)
|
|
|
|
await _process_status_update(workflow_run_id, status_update)
|
|
|
|
return {"status": "success"}
|