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>
175 lines
5.5 KiB
Python
175 lines
5.5 KiB
Python
"""ARI (Asterisk REST Interface) telephony provider package."""
|
|
|
|
from typing import Any, Dict
|
|
|
|
from api.services.telephony.registry import (
|
|
ProviderSpec,
|
|
ProviderUICondition,
|
|
ProviderUIField,
|
|
ProviderUIMetadata,
|
|
ProviderUIOption,
|
|
register,
|
|
)
|
|
|
|
from .config import ARIConfigurationRequest, ARIConfigurationResponse
|
|
from .provider import ARIProvider
|
|
from .transport import create_transport
|
|
|
|
|
|
def _config_loader(value: Dict[str, Any]) -> Dict[str, Any]:
|
|
return {
|
|
"provider": "ari",
|
|
"ari_endpoint": value.get("ari_endpoint"),
|
|
"app_name": value.get("app_name"),
|
|
"app_password": value.get("app_password"),
|
|
"external_pbx": value.get("external_pbx"),
|
|
"from_numbers": value.get("from_numbers", []),
|
|
}
|
|
|
|
|
|
_UI_METADATA = ProviderUIMetadata(
|
|
display_name="Asterisk ARI",
|
|
docs_url="https://docs.dograh.com/integrations/telephony/asterisk-ari",
|
|
fields=[
|
|
ProviderUIField(
|
|
name="ari_endpoint",
|
|
label="ARI Endpoint",
|
|
type="text",
|
|
description="ARI base URL (e.g., http://asterisk.example.com:8088)",
|
|
),
|
|
ProviderUIField(
|
|
name="app_name",
|
|
label="Stasis App Name",
|
|
type="text",
|
|
description="Stasis application name registered in Asterisk",
|
|
),
|
|
ProviderUIField(
|
|
name="app_password",
|
|
label="ARI Password",
|
|
type="password",
|
|
sensitive=True,
|
|
),
|
|
ProviderUIField(
|
|
name="ws_client_name",
|
|
label="websocket_client.conf Name",
|
|
type="text",
|
|
description="websocket_client.conf connection name for externalMedia",
|
|
),
|
|
ProviderUIField(
|
|
name="from_numbers",
|
|
label="From Extensions",
|
|
type="string-array",
|
|
description="SIP extensions/numbers for outbound calls",
|
|
),
|
|
ProviderUIField(
|
|
name="external_pbx.type",
|
|
label="External PBX Type",
|
|
type="select",
|
|
required=False,
|
|
description=(
|
|
"Enable PBX-specific call control for calls patched into Dograh "
|
|
"through this Asterisk configuration."
|
|
),
|
|
options=[ProviderUIOption(value="vicidial", label="VICIdial")],
|
|
section="External PBX",
|
|
feature_gate="external_pbx_integrations",
|
|
),
|
|
ProviderUIField(
|
|
name="external_pbx.agent_api.url",
|
|
label="Agent API URL",
|
|
type="text",
|
|
description="Full VICIdial remote-agent API URL, ending in agc/api.php",
|
|
placeholder="https://vici.example.com/agc/api.php",
|
|
visible_when=ProviderUICondition(
|
|
field="external_pbx.type", equals="vicidial"
|
|
),
|
|
section="External PBX",
|
|
feature_gate="external_pbx_integrations",
|
|
),
|
|
ProviderUIField(
|
|
name="external_pbx.agent_api.username",
|
|
label="Agent API User",
|
|
type="text",
|
|
sensitive=True,
|
|
visible_when=ProviderUICondition(
|
|
field="external_pbx.type", equals="vicidial"
|
|
),
|
|
section="External PBX",
|
|
feature_gate="external_pbx_integrations",
|
|
),
|
|
ProviderUIField(
|
|
name="external_pbx.agent_api.password",
|
|
label="Agent API Password",
|
|
type="password",
|
|
sensitive=True,
|
|
visible_when=ProviderUICondition(
|
|
field="external_pbx.type", equals="vicidial"
|
|
),
|
|
section="External PBX",
|
|
feature_gate="external_pbx_integrations",
|
|
),
|
|
ProviderUIField(
|
|
name="external_pbx.non_agent_api.url",
|
|
label="Non-Agent API URL",
|
|
type="text",
|
|
required=False,
|
|
description=(
|
|
"Optional. Required only when a workflow updates VICIdial lead fields."
|
|
),
|
|
placeholder="https://vici.example.com/vicidial/non_agent_api.php",
|
|
visible_when=ProviderUICondition(
|
|
field="external_pbx.type", equals="vicidial"
|
|
),
|
|
section="External PBX",
|
|
feature_gate="external_pbx_integrations",
|
|
),
|
|
ProviderUIField(
|
|
name="external_pbx.non_agent_api.username",
|
|
label="Non-Agent API User",
|
|
type="text",
|
|
required=False,
|
|
sensitive=True,
|
|
visible_when=ProviderUICondition(
|
|
field="external_pbx.type", equals="vicidial"
|
|
),
|
|
section="External PBX",
|
|
feature_gate="external_pbx_integrations",
|
|
),
|
|
ProviderUIField(
|
|
name="external_pbx.non_agent_api.password",
|
|
label="Non-Agent API Password",
|
|
type="password",
|
|
required=False,
|
|
sensitive=True,
|
|
visible_when=ProviderUICondition(
|
|
field="external_pbx.type", equals="vicidial"
|
|
),
|
|
section="External PBX",
|
|
feature_gate="external_pbx_integrations",
|
|
),
|
|
],
|
|
)
|
|
|
|
|
|
SPEC = ProviderSpec(
|
|
name="ari",
|
|
provider_cls=ARIProvider,
|
|
config_loader=_config_loader,
|
|
transport_factory=create_transport,
|
|
transport_sample_rate=8000,
|
|
config_request_cls=ARIConfigurationRequest,
|
|
ui_metadata=_UI_METADATA,
|
|
config_response_cls=ARIConfigurationResponse,
|
|
)
|
|
|
|
|
|
register(SPEC)
|
|
|
|
|
|
__all__ = [
|
|
"SPEC",
|
|
"ARIConfigurationRequest",
|
|
"ARIConfigurationResponse",
|
|
"ARIProvider",
|
|
"create_transport",
|
|
]
|