import json import logging import urllib.error import urllib.request from ..config import settings logger = logging.getLogger(__name__) def get_ngrok_wss_base() -> str | None: """Detect ngrok public WSS base (test_bonvoice/outbound_call.py pattern).""" tunnel_hosts = ("127.0.0.1:4040", "host.docker.internal:4040") for host in tunnel_hosts: try: with urllib.request.urlopen(f"http://{host}/api/tunnels", timeout=2) as resp: data = json.load(resp) for tunnel in data.get("tunnels", []): public = tunnel.get("public_url", "") if public.startswith("https://"): ngrok_host = public.removeprefix("https://") return f"wss://{ngrok_host}/api/v1/voice" except (urllib.error.URLError, TimeoutError, json.JSONDecodeError, OSError): continue return None def resolve_voice_relay_public_base() -> str: configured = settings.voice_relay_public_url.rstrip("/") if "localhost" in configured or "127.0.0.1" in configured: ngrok_base = get_ngrok_wss_base() if ngrok_base: logger.info("Using ngrok voice relay base: %s", ngrok_base) return ngrok_base return configured def unified_voicebot_url() -> str: """Bonvoice outbound media URL (voicebotURL).""" return f"{resolve_voice_relay_public_base()}/ws/media"