import asyncio import json from livekit import api from livekit.protocol.sip import CreateSIPParticipantRequest from typing import List from src.config import settings def normalize_phone_number(phone_num: str) -> str: """ Ensure phone number is in proper E.164 format with + prefix This is crucial for Twilio SIP termination """ # Remove any existing + prefix clean_num = phone_num.lstrip('+') # Add + prefix for E.164 format return f"+{clean_num}" async def make_call(num: str, roomname: str, prompt: str): """ Create SIP participant with properly formatted phone number """ livekit_api = api.LiveKitAPI( url=settings.LIVEKIT_URL, api_key=settings.LIVEKIT_API_KEY, api_secret=settings.LIVEKIT_API_SECRET ) identity = "user-id" participant_metadata = json.dumps({ "prompt": prompt, }) # Normalize the phone number to E.164 format normalized_number = normalize_phone_number(num) print(f"Calling normalized number: {normalized_number}") request = CreateSIPParticipantRequest( sip_trunk_id=settings.SIP_TRUNK, sip_call_to=normalized_number, # Use normalized E.164 format room_name=roomname, participant_identity=identity, participant_name="new Caller", participant_metadata=participant_metadata, krisp_enabled=True, ) try: participant = await livekit_api.sip.create_sip_participant(request) print(f"Successfully created participant for {normalized_number}: {participant}") return participant except Exception as e: print(f"Error creating SIP participant for {normalized_number}: {str(e)}") # Log the exact request for debugging print(f"Request details: trunk_id={settings.SIP_TRUNK}, call_to={normalized_number}") raise finally: await livekit_api.aclose() async def process_call_list(call_list: List[dict]): """ Process list of calls with proper error handling and logging """ room_name_base = "room-testing" for i, payload in enumerate(call_list): num = payload.get('number') prompt = payload.get('prompt') if not num or not isinstance(prompt, str): print(f"Invalid payload at index {i}: {payload}") continue try: # Create unique room name room_name = f"{room_name_base}_{num.replace('+', '').replace(' ', '')}" print(f"Processing call {i+1}/{len(call_list)} to {num}") await make_call(num, room_name, prompt) # Add delay between calls to avoid rate limiting if i < len(call_list) - 1: # Don't wait after the last call await asyncio.sleep(2) except Exception as e: print(f"Error making call to {num}: {str(e)}") # Continue with next call instead of stopping # Additional debugging function async def test_single_call(phone_number: str, test_prompt: str = "Hello, this is a test call"): """ Test function to make a single call with detailed logging """ print(f"Testing call to: {phone_number}") print(f"Original number: {phone_number}") normalized = normalize_phone_number(phone_number) print(f"Normalized number: {normalized}") room_name = f"test-room-{normalized.replace('+', '').replace(' ', '')}" try: result = await make_call(normalized, room_name, test_prompt) print(f"Test call successful: {result}") return result except Exception as e: print(f"Test call failed: {str(e)}") return None # Example usage for testing async def main(): # Test with your Airtel number airtel_number = "919994893896" # Your Airtel number jio_number = "919876543210" # Replace with your working Jio number print("Testing Airtel number:") await test_single_call(airtel_number, "Hello, this is a test call to Airtel") await asyncio.sleep(5) print("\nTesting Jio number for comparison:") await test_single_call(jio_number, "Hello, this is a test call to Jio") if __name__ == "__main__": asyncio.run(main())