import requests import time import json import os import csv from datetime import datetime # Replace this with your actual API key TELNYX_API_KEY = "KEY0198614F22EB03F1EA32D2AA316730A1_p8o1tpLIuCYXifiDEVfaGH" url = "https://api.telnyx.com/v2/texml/calls/2751729651297551626" headers = { "Authorization": f"Bearer {TELNYX_API_KEY}", "Content-Type": "application/json" } import phonenumbers from phonenumbers import timezone from datetime import datetime import pytz import sys def get_local_time_from_phone(full_number: str) -> int: try: number = phonenumbers.parse(full_number) tz_list = timezone.time_zones_for_number(number) if not tz_list: return -1 # Error code for no timezone found tz = pytz.timezone(tz_list[0]) local_time = datetime.now(tz) return int(local_time.strftime("%H%M")) except: return -1 # Generic error code def map_cause_code_to_status(cause_code): """Map numeric cause codes to readable status strings""" status_map = { 16: "successful", 602: "unanswered", 17: "busy", 1: "invalid_number", 21: "rejected", 0: "failed" } return status_map.get(cause_code, "failed") def load_phone_numbers_from_csv(csv_filename="phone_numbers.csv"): """Load phone numbers and their status from CSV file""" phone_data = [] try: with open(csv_filename, 'r', newline='') as csvfile: reader = csv.DictReader(csvfile) for row in reader: phone_data.append(row) print(f"Loaded {len(phone_data)} phone numbers from {csv_filename}") return phone_data except FileNotFoundError: print(f"CSV file {csv_filename} not found!") return [] except Exception as e: print(f"Error reading CSV file: {e}") return [] def update_csv_with_call_result(csv_filename, phone_number, call_attempted, call_sid, call_status, local_time_check, local_time_value): """Update CSV file with call results""" try: # Read all data phone_data = [] with open(csv_filename, 'r', newline='') as csvfile: reader = csv.DictReader(csvfile) phone_data = list(reader) # Update the specific phone number row current_date = datetime.now().strftime("%Y-%m-%d") for row in phone_data: if row['phone_number'] == phone_number: row['call_attempted'] = str(call_attempted) row['call_sid'] = call_sid if call_sid else "" row['call_status'] = call_status if call_status else "" row['last_attempt_date'] = current_date row['local_time_check'] = str(local_time_check) row['local_time_value'] = str(local_time_value) if local_time_value != -1 else "" break # Write back to CSV with open(csv_filename, 'w', newline='') as csvfile: fieldnames = ['phone_number', 'call_attempted', 'call_sid', 'call_status', 'last_attempt_date', 'local_time_check', 'local_time_value'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerows(phone_data) print(f"Updated CSV for {phone_number}") except Exception as e: print(f"Error updating CSV: {e}") def get_conversation_details(call_control_id): TELNYX_TOKEN = "KEY0198614F22EB03F1EA32D2AA316730A1_p8o1tpLIuCYXifiDEVfaGH" headers = { 'Accept': 'application/json', 'Authorization': f'Bearer {TELNYX_TOKEN}' } payload = {} param = f"metadata->call_control_id=eq.{call_control_id}" url = f"https://api.telnyx.com/v2/ai/conversations?{param}" response = requests.request("GET", url, headers=headers, data=payload) json_obj = response.json() conversation_id = json_obj["data"][0]["id"] if json_obj.get("data") else None if conversation_id: url = f"https://api.telnyx.com/v2/ai/conversations/{conversation_id}/conversations-insights" response = requests.request("GET", url, headers=headers, data=payload) conversation_json = response.json() conversation_insights = conversation_json["data"][0]["conversation_insights"][0]["result"] if conversation_json.get("data") else None return conversation_insights else: return None def get_call_status(call_control_id): # Define the endpoint URL url = f"https://api.telnyx.com/v2/calls/{call_control_id}" # Set up the headers with your API key headers = { "Authorization": f"Bearer {TELNYX_API_KEY}" } # Make the GET request to retrieve the call status response = requests.get(url, headers=headers) # Check if the request was successful if response.status_code == 200: # Parse the response JSON call_details = response.json() #print(call_details) is_alive = call_details['data']['is_alive'] if not is_alive: # Check the call status using cause codes cause_code = call_details['data'].get('cause_code') if cause_code == 16: print("The call was completed normally.") elif cause_code == 602: print("The call went unanswered.") elif cause_code == 17: print("The called party was busy.") elif cause_code == 1: print("The number dialed is invalid.") elif cause_code == 21: print("The call was rejected.") else: print(f"Call ended with cause code: {cause_code}") return cause_code else: cause_code = 1 return cause_code else: print(f"Failed to retrieve call status: {response.status_code} - {response.text}") return 0 # temp = get_call_status('v3:-IAaIq5UpK1UGBTKuc7s7ZzWp580vE8hPX2fMAk-EEh8mY36TKrRwQ') # time.sleep(10000) # Load phone numbers from CSV file csv_filename = "phone_numbers.csv" phone_data = load_phone_numbers_from_csv(csv_filename) if not phone_data: print("No phone numbers loaded from CSV. Exiting.") sys.exit(1) # Create a list to store all call responses all_responses = [] # Create logs directory if it doesn't exist logs_dir = "logs" if not os.path.exists(logs_dir): os.makedirs(logs_dir) print(f"Created logs directory: {logs_dir}") # Use daily filename based on current date current_date = datetime.now().strftime("%Y-%m-%d") json_filename = os.path.join(logs_dir, f"telnyx_calls_{current_date}.json") # Load existing data if file exists for today if os.path.exists(json_filename): try: with open(json_filename, 'r') as f: existing_data = json.load(f) all_responses = existing_data.get('calls', []) print(f"Loaded {len(all_responses)} existing call records from {json_filename}") except (json.JSONDecodeError, KeyError): print(f"Error reading existing file {json_filename}, starting fresh") all_responses = [] else: print(f"Creating new daily log file: {json_filename}") all_responses = [] total_calls, successful_calls = 0,0 for phone_row in phone_data: single_number = phone_row['phone_number'] call_status = phone_row['call_status'] # if call_status is either empty or failed, it can be tried if call_status != '' and call_status != "failed": continue local_time = get_local_time_from_phone(single_number) print(f'Local Time: {local_time}') # Check if local time is within calling hours (10:00 - 19:00) local_time_check_passed = local_time >= 930 and local_time <= 1900 if not local_time_check_passed: print(f'Too late for a call... Time: {local_time}') # Update CSV with local time check failure update_csv_with_call_result(csv_filename, single_number, False, "", "", False, local_time) continue print(f"Calling {single_number}") data = { "From": "+16692056010", "To": single_number } try: response = requests.post(url, headers=headers, json=data) response_json = response.json() print(f"Status Code: {response.status_code}") call_sid = response_json.get("call_sid", None) call_status_code = "NA" call_status_text = "failed" if call_sid: call_status_code = get_call_status(call_sid) #if call is still ongoing while call_status_code == 1: time.sleep(120) call_status_code = get_call_status(call_sid) # Map numeric code to readable status call_status_text = map_cause_code_to_status(call_status_code) if call_status_code == 16: successful_calls = successful_calls + 1 else: call_sid = "NA" call_status_text = "failed" total_calls = total_calls + 1 conversation_insights = get_conversation_details(call_sid) # Update CSV with call results update_csv_with_call_result(csv_filename, single_number, True, call_sid, conversation_insights, True, local_time) call_record = { "timestamp": datetime.now().isoformat(), "phone_number": single_number, "request_data": data, "status_code": response.status_code, "response": response.json() if response.status_code == 200 else response.text, "success": response.status_code == 200, "call_sid": call_sid, "call_status": call_status_code, "call_status_text": call_status_text } print(f"Response: {call_record['response']}") # Add to our collection all_responses.append(call_record) # Save to JSON file after each call (appending to existing data) with open(json_filename, 'w') as f: json.dump({ "date": current_date, "total_calls": len(all_responses), "last_updated": datetime.now().isoformat(), "calls": all_responses }, f, indent=2) print(f"Response appended to {json_filename} (Total calls: {len(all_responses)})") print(f"Total calls: {total_calls}, Successful calls: {successful_calls}") if successful_calls/total_calls < 0.6: time.sleep(900) else: time.sleep(600) except requests.exceptions.RequestException as e: print(f"Error making request to {single_number}: {e}") total_calls = total_calls + 1 # Update CSV with error update_csv_with_call_result(csv_filename, single_number, True, "", "failed", True, local_time) # Still save error information error_record = { "timestamp": datetime.now().isoformat(), "phone_number": single_number, "request_data": data, "error": str(e), "success": False } all_responses.append(error_record) # Update daily JSON file with error info with open(json_filename, 'w') as f: json.dump({ "date": current_date, "total_calls": len(all_responses), "last_updated": datetime.now().isoformat(), "calls": all_responses }, f, indent=2) print(f"Error logged to {json_filename} (Total calls today: {len(all_responses)})") time.sleep(900) except json.JSONDecodeError: print(f"Error decoding JSON response for {single_number}") total_calls = total_calls + 1 # Update CSV with decode error update_csv_with_call_result(csv_filename, single_number, True, "", "failed", True, local_time) # Save raw response if JSON decode fails raw_record = { "timestamp": datetime.now().isoformat(), "phone_number": single_number, "request_data": data, "status_code": response.status_code, "raw_response": response.text, "json_decode_error": True, "success": False } all_responses.append(raw_record) with open(json_filename, 'w') as f: json.dump({ "total_calls": len(all_responses), "last_updated": datetime.now().isoformat(), "calls": all_responses }, f, indent=2) time.sleep(900) print("-" * 50) print(f"\nAll call responses have been saved to: {json_filename}") print(f"Total calls processed: {len(all_responses)}") # Print summary successful_calls = sum(1 for call in all_responses if call.get('success', False)) failed_calls = len(all_responses) - successful_calls print(f"Successful calls: {successful_calls}") print(f"Failed calls: {failed_calls}")