mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-07-22 11:51:04 +02:00
* ViciDial Working * feat(telephony): add FreeSWITCH provider to upstream-PBX seam Generalize the upstream-PBX capture and control paths to dispatch by provider. FreeSWITCH bridges in with X-PBX-* headers and is driven over the Event Socket Library (uuid_kill / uuid_transfer) by the channel UUID, alongside the existing VICIdial ra_call_control path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * add vici specific configs * feat(telephony): env-based VICIdial config + address3 post-call routing Move VICIdial agent/non-agent API and FreeSWITCH ESL connection settings out of hardcoded POC values into environment variables so the same image works against a PBX on another server. Add VICIdial update_lead forwarding: X-VICI-UPDATE-LEAD_* extracted variables are mapped to lead columns and pushed via the non-agent API before a transfer, with reserved API-control params dropped. Add hardcoded address3 disposition routing (Y/N -> in-group transfer, else hang up) and a synchronous final variable extraction so the transfer path sees the freshest conversation state. Skip upstream_pbx capture on non-PJSIP channels to avoid Asterisk 500s. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore: run formatter * feat: make vici configurable from UI * chore: clean up PR * fix: incorporate review comments * chore: incorporate review comments * chore: generate client * chore: incporporate review comments * chore: incorporate review comments --------- Co-authored-by: Dograh POC <payment@dograh.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
75 lines
2.5 KiB
Python
75 lines
2.5 KiB
Python
"""ARI (Asterisk) transport factory."""
|
|
|
|
from fastapi import WebSocket
|
|
from pipecat.transports.websocket.fastapi import (
|
|
FastAPIWebsocketParams,
|
|
FastAPIWebsocketTransport,
|
|
)
|
|
|
|
from api.services.pipecat.audio_config import AudioConfig
|
|
from api.services.pipecat.audio_mixer import build_audio_out_mixer
|
|
from api.services.pipecat.transport_params import realtime_param_overrides
|
|
from api.services.telephony.factory import load_credentials_for_transport
|
|
|
|
from .external_pbx import create_adapter
|
|
from .serializers import AsteriskFrameSerializer
|
|
from .strategies import ARIBridgeSwapStrategy, ARIHangupStrategy
|
|
|
|
|
|
async def create_transport(
|
|
websocket: WebSocket,
|
|
workflow_run_id: int,
|
|
audio_config: AudioConfig,
|
|
organization_id: int,
|
|
*,
|
|
ambient_noise_config: dict | None = None,
|
|
telephony_configuration_id: int | None = None,
|
|
is_realtime: bool = False,
|
|
channel_id: str,
|
|
):
|
|
"""Create a transport for Asterisk ARI connections."""
|
|
config = await load_credentials_for_transport(
|
|
organization_id, telephony_configuration_id, expected_provider="ari"
|
|
)
|
|
|
|
ari_endpoint = config.get("ari_endpoint")
|
|
app_name = config.get("app_name")
|
|
app_password = config.get("app_password")
|
|
|
|
if not ari_endpoint or not app_name or not app_password:
|
|
raise ValueError(
|
|
f"Incomplete ARI configuration for organization {organization_id}. "
|
|
f"Required: ari_endpoint, app_name, app_password"
|
|
)
|
|
|
|
serializer = AsteriskFrameSerializer(
|
|
channel_id=channel_id,
|
|
ari_endpoint=ari_endpoint,
|
|
app_name=app_name,
|
|
app_password=app_password,
|
|
transfer_strategy=ARIBridgeSwapStrategy(),
|
|
hangup_strategy=ARIHangupStrategy(
|
|
external_pbx_adapter=create_adapter(config.get("external_pbx"))
|
|
),
|
|
params=AsteriskFrameSerializer.InputParams(
|
|
asterisk_sample_rate=audio_config.transport_in_sample_rate,
|
|
sample_rate=audio_config.pipeline_sample_rate,
|
|
),
|
|
)
|
|
|
|
mixer = await build_audio_out_mixer(
|
|
audio_config.transport_out_sample_rate, ambient_noise_config
|
|
)
|
|
|
|
return FastAPIWebsocketTransport(
|
|
websocket=websocket,
|
|
params=FastAPIWebsocketParams(
|
|
audio_in_enabled=True,
|
|
audio_out_enabled=True,
|
|
audio_in_sample_rate=audio_config.transport_in_sample_rate,
|
|
audio_out_sample_rate=audio_config.transport_out_sample_rate,
|
|
audio_out_mixer=mixer,
|
|
serializer=serializer,
|
|
**realtime_param_overrides(is_realtime),
|
|
),
|
|
)
|