FILE 1: /home/ai-prank-caller.digitalprank.com/public_html/tool_config.json code JSON { "tool": { "identity": { "slug": "ai-prank-caller", "name": "AI Prank Call Bot", "category": "prank", "tagline": "Unleash hilarious, AI-powered prank calls on your friends!", "description": "Send funny, automated prank calls using AI voices. Type a prank script, pick a voice, and watch the chaos unfold.", "keywords": ["prank call", "ai voice", "funny calls", "voice changer", "digital prank"] }, "features": { "bulk_enabled": false, "history_enabled": true, "export_enabled": true, "api_enabled": true }, "fields": [ { "id": "script_prompt", "type": "text", "label": "Enter your prank script or idea", "placeholder": "e.g., A pizza guy who got lost in your closet.", "required": true, "validation": { "pattern": "^.{10,500}$", "min_length": 10, "max_length": 500 }, "pro_only": false, "help_text": "Describe a scenario like 'An angry neighbor complaining about a barking dog that doesn't exist' or type the full message." }, { "id": "voice_style", "type": "select", "label": "Voice Style", "default": "annoying_robot", "options": [ { "value": "annoying_robot", "label": "Annoying Robot" }, { "value": "squeaky_chipmunk", "label": "Squeaky Chipmunk" }, { "value": "scary_deep", "label": "Scary Deep Voice" }, { "value": "sassy_female", "label": "Sassy Female" }, { "value": "movie_narrator", "label": "Movie Narrator" }, { "value": "angry_neighbor", "label": "Angry Neighbor" }, { "value": "confused_old_lady", "label": "Confused Old Lady" }, { "value": "slick_salesman", "label": "Slick Salesman" }, { "value": "nervous_guy", "label": "Nervous Guy" }, { "value": "custom", "label": "Custom AI-Generated Voice (Pro)" } ], "pro_only": false, "help_text": "Choose a hilarious voice for your prank." }, { "id": "victim_phone", "type": "tel", "label": "Victim's Phone Number", "placeholder": "+15551234567", "required": true, "pro_only": true, "help_text": "Enter the number of your unsuspecting friend. International format required. Pro users only." }, { "id": "caller_id", "type": "tel", "label": "Caller ID to Display (Optional)", "placeholder": "e.g., +15558675309", "required": false, "pro_only": true, "help_text": "What number should appear on their phone? Gold tier and above. Use responsibly." }, { "id": "schedule_time", "type": "datetime", "label": "Schedule Call Time", "required": false, "pro_only": true, "help_text": "Optional. Leave blank to send immediately." }, { "id": "use_ai_voice", "type": "checkbox", "label": "Use AI-Generated Voice", "default": true, "pro_only": false, "help_text": "Let our AI read your script. Uncheck to upload your own audio file (Pro feature)." } ], "limits": { "tier_daily": { "free": 2, "basic": 15, "gold": 150, "ultimate": -1 }, "rate_limit_per_minute": 10, "max_concurrent_requests": 3 }, "billing": { "credit_cost": 1, "one_off_enabled": true, "one_off_price_cents": 99, "bill_on": "success" }, "ui": { "theme": { "primary_color": "#FF4500", "secondary_color": "#1a1a1a" }, "layout": { "show_sidebar_ads": true, "form_style": "wizard", "result_display": "modal" } }, "dependencies": { "php_extensions": ["curl", "json", "mbstring"], "system_packages": ["ffmpeg", "sox"], "python_packages": ["xtts", "pydub", "twilio"], "external_apis": ["twilio", "xtts", "ollama", "openai", "claude"], "requires_internet": true }, "database": { "tool_specific_table": "prank_call_history", "store_results": true, "enable_history": true, "retention_days": 30 }, "seo": { "meta_title": "AI Prank Call Generator | Send Funny Custom Calls | DigitalPrank.com", "meta_description": "Create and send hilarious AI-powered prank calls with funny voices. Type a script, choose a voice like 'Angry Neighbor' or 'Robot', and call your friends. Try it for free!", "canonical_url": "https://digitalprank.com/tools/ai-prank-caller", "structured_data": { "type": "WebApplication", "category": "Entertainment" } }, "help": { "quick_start": [ "Step 1: Type your prank idea or script.", "Step 2: Pick a hilarious voice style.", "Step 3: Enter your victim's phone number (Pro).", "Step 4: Click 'Send Prank Call'!", "Step 5: Enjoy the chaos." ], "faq": [ { "question": "Is this legal?", "answer": "Prank calls can be illegal in some jurisdictions, especially if they involve harassment, threats, or recording without consent. This tool is for entertainment purposes only. Use it responsibly and only with friends who have a good sense of humor. You are responsible for complying with all local and federal laws." }, { "question": "Can I use my own voice?", "answer": "Yes, Pro users can uncheck 'Use AI-Generated Voice' and upload their own pre-recorded audio file." }, { "question": "What if the call doesn't go through?", "answer": "You will not be charged any credits for failed or unanswered calls. You can try again without penalty." } ], "examples": [ { "title": "Wrong Pizza Delivery", "description": "A confused pizza guy calls the wrong number with a strange request.", "input": { "script_prompt": "Hello? I have your extra-large pineapple and anchovy pizza, but I seem to be in your closet. Should I just leave it on the shoe rack?", "voice_style": "nervous_guy" } }, { "title": "Angry Neighbor Complaint", "description": "An angry neighbor calls to complain about a ridiculous noise.", "input": { "script_prompt": "Yeah, hi, this is your neighbor from 3B. I need you to stop teaching your parrot to sing opera. It's scaring my cat, and frankly, you're both off-key.", "voice_style": "angry_neighbor" } } ] }, "monitoring": { "track_usage": true, "track_performance": true, "error_reporting": true, "analytics_events": [ "prank_call_sent", "script_generated", "pro_upgrade" ] }, "security": { "input_sanitization": true, "csrf_protection": true, "rate_limiting": true, "blocked_domains": ["gov", "mil", "911.gov"], "max_input_length": 500, "allowed_file_types": ["mp3", "wav", "txt"] }, "version": { "schema": "3.0.0", "tool": "1.1.0", "api_version": "v1" } } } FILE 2: /home/ai-prank-caller.digitalprank.com/public_html/processor.php code PHP setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'Database connection failed.']); exit; } // Load tool config $tool_slug = 'ai-prank-caller'; $config_path = __DIR__ . '/tool_config.json'; if (!file_exists($config_path)) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'Configuration file not found.']); exit; } $config = json_decode(file_get_contents($config_path), true)['tool']; // Mock User Session session_start(); $user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0; // 0 for guest users $user_ip = $_SERVER['REMOTE_ADDR']; // Basic CSRF check if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { http_response_code(403); echo json_encode(['success' => false, 'message' => 'Invalid session token. Please refresh the page.']); exit; } } $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Regenerate token // Get user access level $access = getUserAccessLevel($pdo, $user_id, $tool_slug); // Get features and apply overrides $features = $config['features']; // In a real app, you would apply specific feature overrides here. $response = [ 'success' => false, 'data' => null, 'usage' => $access['usage'], 'access' => $access, 'features' => $features ]; if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $response['message'] = 'Invalid request method.'; echo json_encode($response); exit; } $input = json_decode(file_get_contents('php://input'), true) ?: $_POST; $start_time = microtime(true); // Daily usage check $limit = $config['limits']['tier_daily'][$access['tier']]; if (!checkDailyUsage($pdo, $tool_slug, $user_ip, $user_id, $limit)) { http_response_code(429); $response['message'] = 'You have exceeded your daily usage limit for this tool.'; echo json_encode($response); exit; } // {{TOOL_PROCESSING_START}} try { // 1. Get and Validate Inputs $errors = []; $validated_input = []; $fields = $config['fields']; $overrides = getToolOverrides($pdo, $tool_slug); foreach ($fields as $field) { $id = $field['id']; $value = isset($input[$id]) ? $input[$id] : null; // Check if field is disabled via override if (isset($overrides[$id]) && $overrides[$id]['override_type'] === 'disabled') { continue; // Skip disabled fields } // Pro field access check $is_pro_field = $field['pro_only']; if (isset($overrides[$id]) && $overrides[$id]['override_type'] === 'tier') { $required_tier_level = getTierLevel($overrides[$id]['tier_required']); if ($access['level'] < $required_tier_level) { $is_pro_field = true; } } if ($is_pro_field && !$access['has_pro_access'] && !empty($value)) { $errors[] = "Field '{$field['label']}' requires a Pro subscription."; continue; } // Required check if ($field['required'] && empty($value)) { $errors[] = "Field '{$field['label']}' is required."; continue; } // Validation Rules if (!empty($value) && isset($field['validation'])) { if (isset($field['validation']['pattern']) && !preg_match('/' . $field['validation']['pattern'] . '/', $value)) { $errors[] = "Invalid format for '{$field['label']}'."; } if (isset($field['validation']['min_length']) && mb_strlen($value) < $field['validation']['min_length']) { $errors[] = "'{$field['label']}' must be at least {$field['validation']['min_length']} characters long."; } if (isset($field['validation']['max_length']) && mb_strlen($value) > $field['validation']['max_length']) { $errors[] = "'{$field['label']}' must not exceed {$field['validation']['max_length']} characters."; } } // Specific validation for phone numbers if (($id === 'victim_phone' || $id === 'caller_id') && !empty($value)) { if (!preg_match('/^\+[1-9]\d{1,14}$/', $value)) { $errors[] = "Invalid phone number format for '{$field['label']}'. Must be in E.164 format (e.g., +15551234567)."; } } $validated_input[$id] = $value; } $use_ai_voice = isset($validated_input['use_ai_voice']) ? filter_var($validated_input['use_ai_voice'], FILTER_VALIDATE_BOOLEAN) : true; $custom_audio_path = null; if (!$use_ai_voice) { if (!$access['has_pro_access']) { $errors[] = "Uploading custom audio is a Pro feature."; } else { // Handle file upload if (isset($_FILES['custom_audio_file']) && $_FILES['custom_audio_file']['error'] === UPLOAD_ERR_OK) { $file = $_FILES['custom_audio_file']; $allowed_types = ['audio/mpeg', 'audio/wav']; if (in_array($file['type'], $allowed_types) && $file['size'] < 5000000) { // 5MB limit $upload_dir = __DIR__ . '/uploads/'; if (!is_dir($upload_dir)) mkdir($upload_dir, 0755, true); $filename = uniqid('audio_', true) . '.' . pathinfo($file['name'], PATHINFO_EXTENSION); $custom_audio_path = $upload_dir . $filename; if (!move_uploaded_file($file['tmp_name'], $custom_audio_path)) { $errors[] = 'Failed to process uploaded audio file.'; $custom_audio_path = null; } } else { $errors[] = 'Invalid file type or size for custom audio. Please use MP3 or WAV under 5MB.'; } } else { $errors[] = "A custom audio file is required when 'Use AI-Generated Voice' is unchecked."; } } } if (!empty($errors)) { throw new Exception(implode(' ', $errors)); } // 2. Implement Tool Functionality $output_data = []; $audio_url_for_call = null; if ($use_ai_voice) { // Simulate generating audio from text using XTTS // In a real scenario, this would call a python script or API $script = escapeshellarg($validated_input['script_prompt']); $voice = escapeshellarg($validated_input['voice_style']); $output_filename = uniqid('prank_', true) . '.wav'; $output_path = '/tmp/' . $output_filename; // Mock command: python3 generate_audio.py --text "text" --voice "voice" --out /path/to/file.wav // $command = "/var/www/venv/ai-prank-caller/bin/python " . __DIR__ . "/generate_audio.py --text {$script} --voice {$voice} --out {$output_path}"; // `{$command}`; // Execute command // For this simulation, we'll just pretend it worked $audio_url_for_call = "https://cdn.digitalprank.com/audio/pranks/{$output_filename}"; $output_data['audio_generation_status'] = 'success'; $output_data['generated_audio_url'] = $audio_url_for_call; } else { // We have a custom audio file, make it accessible via a URL // In reality, you'd move this to a CDN $public_filename = basename($custom_audio_path); $audio_url_for_call = "https://ai-prank-caller.digitalprank.com/uploads/{$public_filename}"; $output_data['custom_audio_status'] = 'processed'; $output_data['generated_audio_url'] = $audio_url_for_call; } // 3. Simulate placing the call with Twilio // In a real app, use the Twilio PHP SDK // require_once 'path/to/vendor/autoload.php'; // use Twilio\Rest\Client; // $twilio_sid = getenv('TWILIO_SID'); // $twilio_token = getenv('TWILIO_AUTH_TOKEN'); // $twilio_client = new Client($twilio_sid, $twilio_token); $call_options = [ 'from' => $access['level'] >= getTierLevel('gold') && !empty($validated_input['caller_id']) ? $validated_input['caller_id'] : getenv('DEFAULT_CALLER_ID'), // Use default number if no caller ID 'url' => $audio_url_for_call ]; // $call = $twilio_client->calls->create( // $validated_input['victim_phone'], // $call_options['from'], // ['url' => $call_options['url']] // ); // Mocked response $call_sid = 'CA' . bin2hex(random_bytes(16)); $status = 'queued'; // Twilio's initial status $output_data['call_sid'] = $call_sid; $output_data['call_status'] = $status; $output_data['message'] = "Prank call successfully initiated to {$validated_input['victim_phone']}."; // 4. Store Results in Database if ($config['database']['store_results']) { $stmt = $pdo->prepare( "INSERT INTO prank_call_history (user_id, victim_phone, caller_id, script, voice, audio_url, call_sid, status, schedule_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" ); $stmt->execute([ $user_id, $validated_input['victim_phone'], $call_options['from'], $validated_input['script_prompt'], $validated_input['voice_style'], $audio_url_for_call, $call_sid, $status, empty($validated_input['schedule_time']) ? null : $validated_input['schedule_time'] ]); } $response['success'] = true; $response['data'] = $output_data; $processing_time = microtime(true) - $start_time; logUsage($pdo, $tool_slug, $user_ip, $user_id, 'success', $input, $output_data, $processing_time, $config['billing']['credit_cost']); } catch (Exception $e) { $response['success'] = false; $response['message'] = $e->getMessage(); http_response_code(400); $processing_time = microtime(true) - $start_time; logUsage($pdo, $tool_slug, $user_ip, $user_id, 'failed', $input, ['error' => $e->getMessage()], $processing_time, 0); } // {{TOOL_PROCESSING_END}} // Final response echo json_encode($response); // Helper function for this tool function getToolOverrides($pdo, $tool_slug) { $stmt = $pdo->prepare("SELECT t.tool_id FROM wp_digitalprank_tools t WHERE t.slug = ?"); $stmt->execute([$tool_slug]); $tool_id = $stmt->fetchColumn(); if (!$tool_id) return []; $stmt = $pdo->prepare("SELECT field_id, tier_required, override_type FROM wp_digitalprank_tool_overrides WHERE tool_id = ? AND is_active = 1"); $stmt->execute([$tool_id]); $overrides = $stmt->fetchAll(PDO::FETCH_KEY_PAIR | PDO::FETCH_GROUP); $result = []; foreach ($overrides as $field_id => $data) { $result[$field_id] = $data[0]; } return $result; } function getTierLevel($tier_name) { $levels = ['free' => 0, 'basic' => 1, 'gold' => 2, 'ultimate' => 3]; return $levels[strtolower($tier_name)] ?? 0; } FILE 3: /home/ai-prank-caller.digitalprank.com/public_html/tool_form.php code PHP false, 'tier' => 'free', 'level' => 0]; // Mock access level for display ?>
>
style="width: auto; margin-right: 10px;">
Processing...
FILE 4: /home/ai-prank-caller.digitalprank.com/public_html/diagnostic.php code PHP Forbidden

Access denied. Valid key required.

'); } function check_status($condition, $success_msg, $failure_msg) { if ($condition) { return "
  • SUCCESS: $success_msg
  • "; } else { return "
  • FAILURE: $failure_msg
  • "; } } function check_shell_command($command, $package_name) { $path = trim(shell_exec("command -v $command")); return check_status(!empty($path), "$package_name is installed ($path).", "$package_name not found in PATH."); } $results = []; // 1. Configuration File Validation $config_path = __DIR__ . '/tool_config.json'; $results['config'] = check_status(file_exists($config_path), "tool_config.json found.", "tool_config.json is missing."); if (file_exists($config_path)) { $config_content = file_get_contents($config_path); json_decode($config_content); $results['config_json'] = check_status(json_last_error() === JSON_ERROR_NONE, "tool_config.json is valid JSON.", "tool_config.json contains invalid JSON: " . json_last_error_msg()); $config = json_decode($config_content, true)['tool']; } else { $config = null; } // 2. Database Connectivity $db_host = 'localhost'; $db_name = 'digitalprank_db'; $db_user = 'dp_user'; $db_pass = '#$Dealer2355'; $pdo = null; try { $pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass); $results['db_connect'] = check_status(true, "Database connection successful.", ""); } catch (PDOException $e) { $results['db_connect'] = check_status(false, "", "Database connection failed: " . $e->getMessage()); } // 3. Table Existence Checks if ($pdo) { $required_tables = [ 'wp_digitalprank_tools', 'wp_digitalprank_usage', 'wp_digitalprank_usage_log', 'wp_pms_member_subscriptions', 'wp_digitalprank_entitlements', 'wp_digitalprank_tool_overrides' ]; if ($config && isset($config['database']['tool_specific_table'])) { $required_tables[] = $config['database']['tool_specific_table']; } foreach ($required_tables as $table) { try { $pdo->query("SELECT 1 FROM `$table` LIMIT 1"); $results["table_$table"] = check_status(true, "Table `$table` exists.", ""); } catch (Exception $e) { $results["table_$table"] = check_status(false, "", "Table `$table` does not exist or is inaccessible."); } } } // 4. Dependencies Checking if ($config) { // PHP Extensions foreach ($config['dependencies']['php_extensions'] as $ext) { $results["php_ext_$ext"] = check_status(extension_loaded($ext), "PHP extension '$ext' is loaded.", "PHP extension '$ext' is NOT loaded."); } // System Packages foreach ($config['dependencies']['system_packages'] as $pkg) { $results["sys_pkg_$pkg"] = check_shell_command($pkg, $pkg); } // Python Packages $venv_path = '/var/www/venv/ai-prank-caller/bin/python'; $results['python_venv'] = check_status(file_exists($venv_path), "Python venv found at $venv_path", "Python venv NOT found at $venv_path"); if(file_exists($venv_path)) { foreach($config['dependencies']['python_packages'] as $pkg) { $check_script = escapeshellarg("import " . explode('==', $pkg)[0]); $command = "$venv_path -c $check_script"; shell_exec("$command 2>&1", $output, $return_code); $results["py_pkg_$pkg"] = check_status($return_code === 0, "Python package '$pkg' is installed in venv.", "Python package '$pkg' is NOT installed in venv."); } } } // 5. Directory Permissions $writable_dirs = [__DIR__ . '/uploads']; foreach ($writable_dirs as $dir) { $is_writable = is_dir($dir) && is_writable($dir); $results["dir_$dir"] = check_status($is_writable, "Directory '$dir' is writable.", "Directory '$dir' is not writable or does not exist."); } ?> AI Prank Call Bot - Diagnostic Report

    Diagnostic Report: AI Prank Call Bot

    Configuration

    Database

    Dependencies

    PHP Extensions

    System Packages

    Python Packages (VENV)

    File System

    FILE 5: /home/ai-prank-caller.digitalprank.com/public_html/help.md code Markdown # AI Prank Call Bot Help Guide Unleash hilarious, AI-powered prank calls on your friends! This guide will walk you through setting up and sending your first prank call. ## Quick Start Guide Getting started is easy. Just follow these steps: 1. **Step 1:** Type your prank idea or script into the "Enter your prank script or idea" field. 2. **Step 2:** Pick a hilarious voice style from the "Voice Style" dropdown menu. 3. **Step 3:** Enter your victim's phone number. This is a Pro feature and requires an active subscription. 4. **Step 4:** Click 'Send Prank Call'! 5. **Step 5:** Enjoy the chaos and wait for your friend's reaction. ## Features * **AI-Generated Voices**: Our advanced AI can read any script you provide in a variety of funny voices. * **Custom Scripts**: You have complete control. Write your own script from scratch for a personalized prank. * **Voice Style Library**: Choose from voices like "Annoying Robot", "Angry Neighbor", and "Confused Old Lady" to perfectly match your prank scenario. * **Custom Audio Upload (Pro)**: Pro users can upload their own MP3 or WAV files instead of using our AI voices. * **Caller ID Spoofing (Gold Tier & Above)**: Make the call appear to come from any number you choose. Please use this feature responsibly. * **Scheduled Calls (Pro)**: Time your prank perfectly by scheduling it to be sent at a future date and time. ## Frequently Asked Questions (FAQ) **Q: Is this legal?** A: Prank calls can be illegal in some jurisdictions, especially if they involve harassment, threats, or recording without consent. This tool is for entertainment purposes only. Use it responsibly and only with friends who have a good sense of humor. You are responsible for complying with all local and federal laws. **Q: Can I use my own voice?** A: Yes, Pro users can uncheck 'Use AI-Generated Voice' and upload their own pre-recorded audio file. **Q: What if the call doesn't go through?** A: You will not be charged any credits for failed or unanswered calls. You can try again without penalty. ## Usage Examples Here are a couple of ideas to get you started: ### Example 1: Wrong Pizza Delivery * **Description**: A confused pizza guy calls the wrong number with a strange request. * **Input**: * **Script Prompt**: `Hello? I have your extra-large pineapple and anchovy pizza, but I seem to be in your closet. Should I just leave it on the shoe rack?` * **Voice Style**: `Nervous Guy` ### Example 2: Angry Neighbor Complaint * **Description**: An angry neighbor calls to complain about a ridiculous noise. * **Input**: * **Script Prompt**: `Yeah, hi, this is your neighbor from 3B. I need you to stop teaching your parrot to sing opera. It's scaring my cat, and frankly, you're both off-key.` * **Voice Style**: `Angry Neighbor` FILE 6: /home/digitalprank.com/public_html/blog/data/tools/ai-prank-caller.json code JSON { "slug": "ai-prank-caller", "name": "AI Prank Call Bot", "meta_title": "AI Prank Call Generator | Send Funny Custom Calls | DigitalPrank.com", "meta_description": "Create and send hilarious AI-powered prank calls with funny voices. Type a script, choose a voice like 'Angry Neighbor' or 'Robot', and call your friends. Try it for free!", "canonical_url": "https://digitalprank.com/tools/ai-prank-caller", "long_description": "Our AI Prank Call Bot is the ultimate tool for harmless fun. Using cutting-edge text-to-speech technology, you can type any scenario and have it performed by a unique AI voice personality. From a squeaky chipmunk to a booming movie narrator, the possibilities are endless. Pro users can even schedule calls, set a custom caller ID, or upload their own audio for the ultimate personalized prank.", "features_list": [ { "name": "Text-to-Speech Engine", "description": "Our AI converts your text script into natural-sounding, funny audio.", "is_pro": false }, { "name": "Multiple Voice Styles", "description": "Choose from a library of voices including robots, angry neighbors, and more.", "is_pro": false }, { "name": "Phone Number Targeting", "description": "Send your prank call directly to your friend's phone number.", "is_pro": true }, { "name": "Custom Caller ID", "description": "Set the phone number that appears on the recipient's caller ID.", "is_pro": true, "tier": "gold" }, { "name": "Call Scheduling", "description": "Plan your prank in advance by scheduling the call for a specific time.", "is_pro": true }, { "name": "Upload Custom Audio", "description": "Use your own pre-recorded MP3 or WAV files for the prank.", "is_pro": true } ], "user_guide": { "title": "How to Send an AI Prank Call", "steps": [ "Enter your prank script in the text box. Be creative!", "Select a voice from the dropdown that best fits the prank.", "If you are a Pro user, enter the recipient's full phone number in international format (e.g., +15551234567).", "Optionally, Pro users can set a custom Caller ID or schedule the call.", "Click 'Send Prank Call' and let our system handle the rest." ], "best_practices": "For the best results, keep scripts short and to the point. Use voices that contrast with the message for extra humor. Always ensure your prank is harmless and that the recipient will find it funny. Do not use this service for harassment." }, "structured_data": { "@context": "https://schema.org", "@type": "WebApplication", "name": "AI Prank Call Bot", "description": "Send hilarious, AI-powered prank calls with custom scripts and funny voices.", "url": "https://digitalprank.com/tools/ai-prank-caller", "applicationCategory": "EntertainmentApplication", "operatingSystem": "Any (Web-based)", "offers": { "@type": "Offer", "price": "0.00", "priceCurrency": "USD", "description": "Free tier with 2 daily calls." }, "softwareHelp": { "@type": "CreativeWork", "name": "AI Prank Call Bot Help & FAQ" } } } FILE 7: /home/ai-prank-caller.digitalprank.com/public_html/deploy.sh code Bash #!/bin/bash # Deployment script for the AI Prank Call Bot tool # This script must be run with root privileges. set -e TOOL_SLUG="ai-prank-caller" TOOL_DOMAIN="${TOOL_SLUG}.digitalprank.com" TOOL_ROOT="/home/${TOOL_DOMAIN}/public_html" VENV_PATH="/var/www/venv/${TOOL_SLUG}" DB_NAME='digitalprank_db' DB_USER='dp_user' DB_PASS='#$Dealer2355' echo "--- Starting deployment for ${TOOL_SLUG} ---" # 1. Install System Packages echo "[TASK 1/8] Installing system packages (ffmpeg, sox)..." apt-get update apt-get install -y ffmpeg sox # 2. Install PHP Extensions (Assuming a common environment like Docker) echo "[TASK 2/8] Ensuring PHP extensions are installed (curl, json, mbstring)..." # In a real environment, you might use: docker-php-ext-install curl json mbstring # For this script, we'll assume they are available or installed via another process. php -m | grep -q 'curl' || echo "WARNING: curl PHP extension not found." php -m | grep -q 'json' || echo "WARNING: json PHP extension not found." php -m | grep -q 'mbstring' || echo "WARNING: mbstring PHP extension not found." # 3. Create Python Virtual Environment and Install Packages echo "[TASK 3/8] Setting up Python virtual environment..." if [ ! -d "${VENV_PATH}" ]; then python3 -m venv "${VENV_PATH}" echo "Created Python venv at ${VENV_PATH}" fi echo "Installing Python packages (xtts, pydub, twilio)..." source "${VENV_PATH}/bin/activate" pip install --upgrade pip pip install xtts-cli pydub twilio deactivate echo "Python packages installed." # 4. Create Tool-Specific Database Table echo "[TASK 4/8] Creating database table 'prank_call_history'..." SQL_CREATE_TABLE=" CREATE TABLE IF NOT EXISTS \`prank_call_history\` ( \`id\` BIGINT PRIMARY KEY AUTO_INCREMENT, \`user_id\` BIGINT NOT NULL, \`victim_phone\` VARCHAR(20) NOT NULL, \`caller_id\` VARCHAR(20), \`script\` TEXT, \`voice\` VARCHAR(50), \`audio_url\` VARCHAR(255), \`call_sid\` VARCHAR(255) UNIQUE, \`status\` VARCHAR(20) DEFAULT 'pending', \`schedule_time\` DATETIME NULL, \`created_at\` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, \`updated_at\` TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX \`user_id_idx\` (\`user_id\`), INDEX \`status_idx\` (\`status\`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; " mysql -u"${DB_USER}" -p"${DB_PASS}" "${DB_NAME}" -e "${SQL_CREATE_TABLE}" echo "Database table ensured." # 5. Create Directories and Set Permissions echo "[TASK 5/8] Creating directories and setting permissions..." mkdir -p "${TOOL_ROOT}/uploads" chown -R www-data:www-data "/home/${TOOL_DOMAIN}" chmod -R 755 "/home/${TOOL_DOMAIN}" chmod 775 "${TOOL_ROOT}/uploads" # Allow web server to write uploads echo "Directory structure created." # 6. Configure OpenLiteSpeed Virtual Host echo "[TASK 6/8] Configuring OpenLiteSpeed virtual host..." OLS_VH_CONFIG=" virtualHost ${TOOL_SLUG} { vhRoot ${TOOL_ROOT} configFile \$SERVER_ROOT/conf/vhosts/${TOOL_SLUG}/vhost.conf allowSymbolLink 1 enableScript 1 restrained 1 setUIDMode 0 } " # This would typically be appended to the main LiteSpeed config, # and a specific vhost.conf would be created. # For simplicity, we echo the config block. echo "OpenLiteSpeed config block for ${TOOL_DOMAIN}:" echo "------------------------------------------------" echo "${OLS_VH_CONFIG}" echo "------------------------------------------------" echo "NOTE: Manual addition to OpenLiteSpeed configuration may be required." # 7. Setup Log Rotation echo "[TASK 7/8] Setting up log rotation..." LOGROTATE_CONFIG="/etc/logrotate.d/${TOOL_SLUG}" cat > "${LOGROTATE_CONFIG}" << EOL ${TOOL_ROOT}/logs/*.log { daily missingok rotate 14 compress delaycompress notifempty create 640 www-data adm sharedscripts } EOL echo "Log rotation configured at ${LOGROTATE_CONFIG}" # 8. Final Health Check echo "[TASK 8/8] Performing final health check..." # A simple curl to the diagnostic script to confirm setup HEALTH_CHECK_URL="http://${TOOL_DOMAIN}/diagnostic.php?key=digitalprank2025" echo "To complete health check, ensure DNS is pointing to this server and run:" echo "curl -I ${HEALTH_CHECK_URL}" echo "--- Deployment for ${TOOL_SLUG} complete! ---" Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 1: /home/ai-prank-caller.digitalprank.com/public_html/tool_config.json code JSON { "tool": { "identity": { "slug": "ai-prank-caller", "name": "AI Prank Call Bot", "category": "prank", "tagline": "Unleash hilarious, AI-powered prank calls on your friends!", "description": "Send funny, automated prank calls using AI voices. Type a prank script, pick a voice, and watch the chaos unfold.", "keywords": ["prank call", "ai voice", "funny calls", "voice changer", "digital prank"] }, "features": { "bulk_enabled": false, "history_enabled": true, "export_enabled": true, "api_enabled": true }, "fields": [ { "id": "script_prompt", "type": "text", "label": "Enter your prank script or idea", "placeholder": "e.g., A pizza guy who got lost in your closet.", "required": true, "validation": { "pattern": "^.{10,500}$", "min_length": 10, "max_length": 500 }, "pro_only": false, "help_text": "Describe a scenario like 'An angry neighbor complaining about a barking dog that doesn't exist' or type the full message." }, { "id": "voice_style", "type": "select", "label": "Voice Style", "default": "annoying_robot", "options": [ { "value": "annoying_robot", "label": "Annoying Robot" }, { "value": "squeaky_chipmunk", "label": "Squeaky Chipmunk" }, { "value": "scary_deep", "label": "Scary Deep Voice" }, { "value": "sassy_female", "label": "Sassy Female" }, { "value": "movie_narrator", "label": "Movie Narrator" }, { "value": "angry_neighbor", "label": "Angry Neighbor" }, { "value": "confused_old_lady", "label": "Confused Old Lady" }, { "value": "slick_salesman", "label": "Slick Salesman" }, { "value": "nervous_guy", "label": "Nervous Guy" }, { "value": "custom", "label": "Custom AI-Generated Voice (Pro)" } ], "pro_only": false, "help_text": "Choose a hilarious voice for your prank." }, { "id": "victim_phone", "type": "tel", "label": "Victim's Phone Number", "placeholder": "+15551234567", "required": true, "pro_only": true, "help_text": "Enter the number of your unsuspecting friend. International format required. Pro users only." }, { "id": "caller_id", "type": "tel", "label": "Caller ID to Display (Optional)", "placeholder": "e.g., +15558675309", "required": false, "pro_only": true, "help_text": "What number should appear on their phone? Gold tier and above. Use responsibly." }, { "id": "schedule_time", "type": "datetime", "label": "Schedule Call Time", "required": false, "pro_only": true, "help_text": "Optional. Leave blank to send immediately." }, { "id": "use_ai_voice", "type": "checkbox", "label": "Use AI-Generated Voice", "default": true, "pro_only": false, "help_text": "Let our AI read your script. Uncheck to upload your own audio file (Pro feature)." } ], "limits": { "tier_daily": { "free": 2, "basic": 15, "gold": 150, "ultimate": -1 }, "rate_limit_per_minute": 10, "max_concurrent_requests": 3 }, "billing": { "credit_cost": 1, "one_off_enabled": true, "one_off_price_cents": 99, "bill_on": "success" }, "ui": { "theme": { "primary_color": "#FF4500", "secondary_color": "#1a1a1a" }, "layout": { "show_sidebar_ads": true, "form_style": "wizard", "result_display": "modal" } }, "dependencies": { "php_extensions": ["curl", "json", "mbstring"], "system_packages": ["ffmpeg", "sox"], "python_packages": ["xtts", "pydub", "twilio"], "external_apis": ["twilio", "xtts", "ollama", "openai", "claude"], "requires_internet": true }, "database": { "tool_specific_table": "prank_call_history", "store_results": true, "enable_history": true, "retention_days": 30 }, "seo": { "meta_title": "AI Prank Call Generator | Send Funny Custom Calls | DigitalPrank.com", "meta_description": "Create and send hilarious AI-powered prank calls with funny voices. Type a script, choose a voice like 'Angry Neighbor' or 'Robot', and call your friends. Try it for free!", "canonical_url": "https://digitalprank.com/tools/ai-prank-caller", "structured_data": { "type": "WebApplication", "category": "Entertainment" } }, "help": { "quick_start": [ "Step 1: Type your prank idea or script.", "Step 2: Pick a hilarious voice style.", "Step 3: Enter your victim's phone number (Pro).", "Step 4: Click 'Send Prank Call'!", "Step 5: Enjoy the chaos." ], "faq": [ { "question": "Is this legal?", "answer": "Prank calls can be illegal in some jurisdictions, especially if they involve harassment, threats, or recording without consent. This tool is for entertainment purposes only. Use it responsibly and only with friends who have a good sense of humor. You are responsible for complying with all local and federal laws." }, { "question": "Can I use my own voice?", "answer": "Yes, Pro users can uncheck 'Use AI-Generated Voice' and upload their own pre-recorded audio file." }, { "question": "What if the call doesn't go through?", "answer": "You will not be charged any credits for failed or unanswered calls. You can try again without penalty." } ], "examples": [ { "title": "Wrong Pizza Delivery", "description": "A confused pizza guy calls the wrong number with a strange request.", "input": { "script_prompt": "Hello? I have your extra-large pineapple and anchovy pizza, but I seem to be in your closet. Should I just leave it on the shoe rack?", "voice_style": "nervous_guy" } }, { "title": "Angry Neighbor Complaint", "description": "An angry neighbor calls to complain about a ridiculous noise.", "input": { "script_prompt": "Yeah, hi, this is your neighbor from 3B. I need you to stop teaching your parrot to sing opera. It's scaring my cat, and frankly, you're both off-key.", "voice_style": "angry_neighbor" } } ] }, "monitoring": { "track_usage": true, "track_performance": true, "error_reporting": true, "analytics_events": [ "prank_call_sent", "script_generated", "pro_upgrade" ] }, "security": { "input_sanitization": true, "csrf_protection": true, "rate_limiting": true, "blocked_domains": ["gov", "mil", "911.gov"], "max_input_length": 500, "allowed_file_types": ["mp3", "wav", "txt"] }, "version": { "schema": "3.0.0", "tool": "1.1.0", "api_version": "v1" } } } FILE 2: /home/ai-prank-caller.digitalprank.com/public_html/processor.php code PHP setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'Database connection failed.']); exit; } // Load tool config $tool_slug = 'ai-prank-caller'; $config_path = __DIR__ . '/tool_config.json'; if (!file_exists($config_path)) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'Configuration file not found.']); exit; } $config = json_decode(file_get_contents($config_path), true)['tool']; // Mock User Session session_start(); $user_id = isset($_SESSION['user_id']) ? $_SESSION['user_id'] : 0; // 0 for guest users $user_ip = $_SERVER['REMOTE_ADDR']; // Basic CSRF check if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (!isset($_POST['csrf_token']) || !isset($_SESSION['csrf_token']) || $_POST['csrf_token'] !== $_SESSION['csrf_token']) { http_response_code(403); echo json_encode(['success' => false, 'message' => 'Invalid session token. Please refresh the page.']); exit; } } $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Regenerate token // Get user access level $access = getUserAccessLevel($pdo, $user_id, $tool_slug); // Get features and apply overrides $features = $config['features']; // In a real app, you would apply specific feature overrides here. $response = [ 'success' => false, 'data' => null, 'usage' => $access['usage'], 'access' => $access, 'features' => $features ]; if ($_SERVER['REQUEST_METHOD'] !== 'POST') { $response['message'] = 'Invalid request method.'; echo json_encode($response); exit; } $input = $_POST; $start_time = microtime(true); // Daily usage check $limit = $config['limits']['tier_daily'][$access['tier']]; if (!checkDailyUsage($pdo, $tool_slug, $user_ip, $user_id, $limit)) { http_response_code(429); $response['message'] = 'You have exceeded your daily usage limit for this tool.'; echo json_encode($response); exit; } // {{TOOL_PROCESSING_START}} try { // 1. Get and Validate Inputs $errors = []; $validated_input = []; $fields = $config['fields']; $overrides = getToolOverrides($pdo, $tool_slug); foreach ($fields as $field) { $id = $field['id']; $value = isset($input[$id]) ? trim($input[$id]) : null; // Check if field is disabled via override if (isset($overrides[$id]) && $overrides[$id]['override_type'] === 'disabled') { continue; // Skip disabled fields } // Pro field access check $is_pro_field = $field['pro_only']; $required_tier_level = 0; // 0 = free if (isset($overrides[$id]) && $overrides[$id]['override_type'] === 'tier') { $required_tier_level = getTierLevel($overrides[$id]['tier_required']); } if (($is_pro_field || $required_tier_level > 0) && $access['level'] < $required_tier_level && !empty($value)) { $errors[] = "Field '{$field['label']}' requires a higher subscription tier."; continue; } // Required check if ($field['required'] && ($value === null || $value === '')) { $errors[] = "Field '{$field['label']}' is required."; continue; } // Validation Rules if (!empty($value) && isset($field['validation'])) { if (isset($field['validation']['pattern']) && !preg_match('/' . $field['validation']['pattern'] . '/s', $value)) { $errors[] = "Invalid format for '{$field['label']}'."; } if (isset($field['validation']['min_length']) && mb_strlen($value) < $field['validation']['min_length']) { $errors[] = "'{$field['label']}' must be at least {$field['validation']['min_length']} characters long."; } if (isset($field['validation']['max_length']) && mb_strlen($value) > $field['validation']['max_length']) { $errors[] = "'{$field['label']}' must not exceed {$field['validation']['max_length']} characters."; } } // Specific validation for phone numbers if (($id === 'victim_phone' || $id === 'caller_id') && !empty($value)) { if (!preg_match('/^\+[1-9]\d{1,14}$/', $value)) { $errors[] = "Invalid phone number format for '{$field['label']}'. Must be in E.164 format (e.g., +15551234567)."; } foreach ($config['security']['blocked_domains'] as $domain) { if(str_contains($value, $domain)) { $errors[] = "Calling emergency or government services is strictly prohibited."; } } } $validated_input[$id] = $value; } $use_ai_voice = !(isset($validated_input['use_ai_voice']) && $validated_input['use_ai_voice'] === '0'); $custom_audio_path = null; if (!$use_ai_voice) { if (!$access['has_pro_access']) { $errors[] = "Uploading custom audio is a Pro feature."; } else { // Handle file upload if (isset($_FILES['custom_audio_file']) && $_FILES['custom_audio_file']['error'] === UPLOAD_ERR_OK) { $file = $_FILES['custom_audio_file']; $allowed_types = ['audio/mpeg', 'audio/wav', 'audio/x-wav']; if (in_array($file['type'], $allowed_types) && $file['size'] < 5000000) { // 5MB limit $upload_dir = __DIR__ . '/uploads/'; if (!is_dir($upload_dir)) mkdir($upload_dir, 0755, true); $filename = uniqid('audio_', true) . '.' . pathinfo($file['name'], PATHINFO_EXTENSION); $custom_audio_path = $upload_dir . $filename; if (!move_uploaded_file($file['tmp_name'], $custom_audio_path)) { $errors[] = 'Failed to process uploaded audio file.'; $custom_audio_path = null; } } else { $errors[] = 'Invalid file type or size for custom audio. Please use MP3 or WAV under 5MB.'; } } else { $errors[] = "A custom audio file is required when 'Use AI-Generated Voice' is unchecked."; } } } if (!empty($errors)) { throw new Exception(implode(' ', $errors)); } // 2. Implement Tool Functionality $output_data = []; $audio_url_for_call = null; if ($use_ai_voice) { // Simulate generating audio from text using XTTS $venv_python = "/var/www/venv/ai-prank-caller/bin/python"; $script_path = __DIR__ . "/generate_audio.py"; // A helper script you would create $script = escapeshellarg($validated_input['script_prompt']); $voice = escapeshellarg($validated_input['voice_style']); $output_filename = uniqid('prank_', true) . '.wav'; $output_path = "/tmp/" . $output_filename; // Mock command: This would call a real text-to-speech script // $command = "{$venv_python} {$script_path} --text {$script} --voice {$voice} --out {$output_path}"; // shell_exec($command); // For this simulation, we'll create a placeholder and URL file_put_contents($output_path, "This is a custom audio file for testing."); $audio_url_for_call = "https://cdn.digitalprank.com/audio/pranks/{$output_filename}"; // In reality, you'd upload $output_path to the CDN $output_data['audio_generation_status'] = 'success'; $output_data['generated_audio_url'] = $audio_url_for_call; } else { // We have a custom audio file, make it accessible via a URL $public_filename = basename($custom_audio_path); $audio_url_for_call = "https://ai-prank-caller.digitalprank.com/uploads/{$public_filename}"; $output_data['custom_audio_status'] = 'processed'; $output_data['generated_audio_url'] = $audio_url_for_call; } // 3. Simulate placing the call with Twilio // In a real app, use the Twilio PHP SDK: require 'vendor/autoload.php'; // use Twilio\Rest\Client; $caller_id_to_use = getenv('DEFAULT_TWILIO_NUMBER'); // A verified number in your Twilio account if ($access['level'] >= getTierLevel('gold') && !empty($validated_input['caller_id'])) { $caller_id_to_use = $validated_input['caller_id']; } // $twilio = new Client(getenv('TWILIO_ACCOUNT_SID'), getenv('TWILIO_AUTH_TOKEN')); // $call = $twilio->calls->create( $validated_input['victim_phone'], $caller_id_to_use, ["url" => $audio_url_for_call] ); // $call_sid = $call->sid; // $status = $call->status; // Mocked response for demonstration $call_sid = 'CA' . bin2hex(random_bytes(16)); $status = 'queued'; $output_data['call_sid'] = $call_sid; $output_data['call_status'] = $status; $output_data['message'] = "Prank call successfully initiated to {$validated_input['victim_phone']}."; // 4. Store Results in Database if ($config['database']['store_results'] && $config['database']['enable_history']) { $stmt = $pdo->prepare( "INSERT INTO prank_call_history (user_id, victim_phone, caller_id, script, voice, audio_url, call_sid, status, schedule_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)" ); $stmt->execute([ $user_id, $validated_input['victim_phone'], $caller_id_to_use, $validated_input['script_prompt'], $validated_input['voice_style'], $audio_url_for_call, $call_sid, $status, empty($validated_input['schedule_time']) ? null : $validated_input['schedule_time'] ]); } $response['success'] = true; $response['data'] = $output_data; $processing_time = microtime(true) - $start_time; logUsage($pdo, $tool_slug, $user_ip, $user_id, 'success', $input, $output_data, $processing_time, $config['billing']['credit_cost']); } catch (Exception $e) { $response['success'] = false; $response['message'] = $e->getMessage(); http_response_code(400); $processing_time = microtime(true) - $start_time; logUsage($pdo, $tool_slug, $user_ip, $user_id, 'failed', $input, ['error' => $e->getMessage()], $processing_time, 0); } // {{TOOL_PROCESSING_END}} // Final response echo json_encode($response); // Helper function for this tool function getToolOverrides($pdo, $tool_slug) { $stmt = $pdo->prepare("SELECT tool_id FROM wp_digitalprank_tools WHERE slug = ?"); $stmt->execute([$tool_slug]); $tool_id = $stmt->fetchColumn(); if (!$tool_id) return []; $stmt = $pdo->prepare("SELECT field_id, tier_required, override_type FROM wp_digitalprank_tool_overrides WHERE tool_id = ? AND is_active = 1"); $stmt->execute([$tool_id]); $overrides = $stmt->fetchAll(PDO::FETCH_ASSOC); $result = []; foreach ($overrides as $override) { $result[$override['field_id']] = $override; } return $result; } function getTierLevel($tier_name) { $levels = ['free' => 0, 'basic' => 1, 'gold' => 2, 'ultimate' => 3]; return $levels[strtolower($tier_name)] ?? 0; } FILE 3: /home/ai-prank-caller.digitalprank.com/public_html/tool_form.php code PHP false, 'tier' => 'free', 'level' => 0]; ?>
    >

    Processing...

    FILE 4: /home/ai-prank-caller.digitalprank.com/public_html/diagnostic.php code PHP Forbidden

    Access denied. Valid key required.

    '); } function check_status($condition, $success_msg, $failure_msg, &$status_list) { if ($condition) { $status_list[] = "
  • OK: $success_msg
  • "; } else { $status_list[] = "
  • FAIL: $failure_msg
  • "; } } function check_shell_command($command, $package_name, &$status_list) { $path = trim(shell_exec("command -v $command")); check_status(!empty($path), "$package_name is installed (path: $path).", "$package_name could not be found in the system's PATH.", $status_list); } $results = []; // 1. Configuration File Validation $config_path = __DIR__ . '/tool_config.json'; check_status(file_exists($config_path) && is_readable($config_path), "tool_config.json found and is readable.", "tool_config.json is missing or not readable.", $results['Configuration']); $config = null; if (file_exists($config_path)) { $config_content = file_get_contents($config_path); json_decode($config_content); check_status(json_last_error() === JSON_ERROR_NONE, "tool_config.json is valid JSON.", "tool_config.json contains invalid JSON: " . json_last_error_msg(), $results['Configuration']); $config = json_decode($config_content, true)['tool']; } // 2. Database $db_host = 'localhost'; $db_name = 'digitalprank_db'; $db_user = 'dp_user'; $db_pass = '#$Dealer2355'; $pdo = null; try { $pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass); check_status(true, "Database connection to '$db_name' successful.", "", $results['Database']); } catch (PDOException $e) { check_status(false, "", "Database connection failed: " . htmlspecialchars($e->getMessage()), $results['Database']); } // 3. Table Existence if ($pdo) { $required_tables = [ 'wp_digitalprank_tools', 'wp_digitalprank_usage', 'wp_digitalprank_usage_log', 'wp_pms_member_subscriptions', 'wp_digitalprank_entitlements', 'wp_digitalprank_tool_overrides' ]; if ($config && isset($config['database']['tool_specific_table'])) { $required_tables[] = $config['database']['tool_specific_table']; } foreach ($required_tables as $table) { try { $pdo->query("SELECT 1 FROM `$table` LIMIT 1"); check_status(true, "Table `{$table}` exists.", "", $results['Database Tables']); } catch (Exception $e) { check_status(false, "", "Table `{$table}` does not exist or is inaccessible.", $results['Database Tables']); } } } // 4. Dependencies if ($config) { foreach ($config['dependencies']['php_extensions'] as $ext) { check_status(extension_loaded($ext), "PHP extension '{$ext}' is loaded.", "PHP extension '{$ext}' is NOT loaded.", $results['PHP Dependencies']); } foreach ($config['dependencies']['system_packages'] as $pkg) { check_shell_command($pkg, $pkg, $results['System Dependencies']); } $venv_path = '/var/www/venv/ai-prank-caller/bin/python'; check_status(file_exists($venv_path) && is_executable($venv_path), "Python venv executable found at {$venv_path}", "Python venv NOT found or not executable at {$venv_path}", $results['Python Dependencies']); if(file_exists($venv_path)) { foreach($config['dependencies']['python_packages'] as $pkg) { $pkg_name = explode('==', $pkg)[0]; $check_script = escapeshellarg("import " . $pkg_name); $command = "$venv_path -c $check_script"; shell_exec("$command 2>&1", $output, $return_code); check_status($return_code === 0, "Python package '{$pkg}' appears to be installed.", "Python package '{$pkg}' is NOT installed or importable.", $results['Python Dependencies']); } } } // 5. File System Permissions $writable_dirs = [__DIR__ . '/uploads']; foreach ($writable_dirs as $dir) { $exists = file_exists($dir); $is_writable = $exists && is_writable($dir); check_status($is_writable, "Directory '{$dir}' is writable.", "Directory '{$dir}' is not writable or does not exist.", $results['File System']); } ?> Diagnostic Report: AI Prank Call Bot

    Diagnostic Report: AI Prank Call Bot

    $checks): ?>

    FILE 5: /home/ai-prank-caller.digitalprank.com/public_html/help.md code Markdown # AI Prank Call Bot Help Guide Unleash hilarious, AI-powered prank calls on your friends! This guide will walk you through setting up and sending your first prank call. ## Quick Start Guide Getting started is easy. Just follow these steps: 1. **Step 1:** Type your prank idea or script into the "Enter your prank script or idea" field. 2. **Step 2:** Pick a hilarious voice style from the "Voice Style" dropdown menu. 3. **Step 3:** Enter your victim's phone number. This is a **Pro feature** and requires an active subscription. 4. **Step 4:** Click 'Send Prank Call'! 5. **Step 5:** Enjoy the chaos and wait for your friend's reaction. ## Features * **AI-Generated Voices**: Our advanced AI can read any script you provide in a variety of funny voices. * **Custom Scripts**: You have complete control. Write your own script from scratch for a personalized prank. * **Voice Style Library**: Choose from voices like "Annoying Robot", "Angry Neighbor", and "Confused Old Lady" to perfectly match your prank scenario. * **Custom Audio Upload (Pro)**: Pro users can uncheck 'Use AI-Generated Voice' and upload their own MP3 or WAV files instead of using our AI voices. * **Caller ID Spoofing (Gold Tier & Above)**: Make the call appear to come from any number you choose. Please use this feature responsibly. * **Scheduled Calls (Pro)**: Time your prank perfectly by scheduling it to be sent at a future date and time. ## Frequently Asked Questions (FAQ) ### Is this legal? Prank calls can be illegal in some jurisdictions, especially if they involve harassment, threats, or recording without consent. This tool is for entertainment purposes only. Use it responsibly and only with friends who have a good sense of humor. You are responsible for complying with all local and federal laws. ### Can I use my own voice? Yes, Pro users can uncheck 'Use AI-Generated Voice' and upload their own pre-recorded audio file. ### What if the call doesn't go through? You will not be charged any credits for failed or unanswered calls. You can try again without penalty. ## Usage Examples Here are a couple of ideas to get you started: ### Example 1: Wrong Pizza Delivery * **Description**: A confused pizza guy calls the wrong number with a strange request. * **Input**: * **Script Prompt**: `Hello? I have your extra-large pineapple and anchovy pizza, but I seem to be in your closet. Should I just leave it on the shoe rack?` * **Voice Style**: `nervous_guy` ### Example 2: Angry Neighbor Complaint * **Description**: An angry neighbor calls to complain about a ridiculous noise. * **Input**: * **Script Prompt**: `Yeah, hi, this is your neighbor from 3B. I need you to stop teaching your parrot to sing opera. It's scaring my cat, and frankly, you're both off-key.` * **Voice Style**: `angry_neighbor` FILE 6: /home/digitalprank.com/public_html/blog/data/tools/ai-prank-caller.json code JSON { "slug": "ai-prank-caller", "name": "AI Prank Call Bot", "meta_title": "AI Prank Call Generator | Send Funny Custom Calls | DigitalPrank.com", "meta_description": "Create and send hilarious AI-powered prank calls with funny voices. Type a script, choose a voice like 'Angry Neighbor' or 'Robot', and call your friends. Try it for free!", "canonical_url": "https://digitalprank.com/tools/ai-prank-caller", "long_description": "Unleash the ultimate prank with the AI Prank Call Bot from DigitalPrank.com. Our advanced tool uses cutting-edge text-to-speech technology, allowing you to type any script and have it performed by a unique AI voice personality. Whether you want to sound like a squeaky chipmunk, a confused old lady, or a booming movie narrator, the possibilities are endless. It's the perfect tool for harmless fun and getting a laugh out of your friends. Pro users can unlock even more powerful features, including scheduling calls for the perfect moment, setting a custom caller ID, or even uploading their own audio for a truly personalized prank experience.", "features_list": [ { "name": "Advanced Text-to-Speech Engine", "description": "Our powerful AI converts your text script into natural-sounding and hilarious audio in seconds.", "is_pro": false }, { "name": "Diverse Voice Library", "description": "Choose from a wide library of distinct voices including robots, angry neighbors, slick salesmen, and more to fit any scenario.", "is_pro": false }, { "name": "Direct-to-Phone Calling", "description": "Send your hilarious, AI-generated prank call directly to your friend's phone number.", "is_pro": true }, { "name": "Custom Caller ID (Gold+)", "description": "Set the phone number that appears on the recipient's caller ID for added believability or humor.", "is_pro": true, "tier": "gold" }, { "name": "Scheduled Prank Calls", "description": "Plan your prank in advance by scheduling the call to be sent at the exact date and time you choose.", "is_pro": true }, { "name": "Upload Custom Audio", "description": "For the ultimate custom prank, upload your own pre-recorded MP3 or WAV files to be used in the call.", "is_pro": true } ], "user_guide": { "title": "How to Send Your First AI Prank Call in Seconds", "steps": [ "Craft your perfect prank script in the text box. Let your imagination run wild!", "Select a voice from the dropdown menu that best fits the prank's character.", "If you're a Pro user, enter the recipient's full phone number in international format (e.g., +15551234567).", "Optionally, Pro users can set a custom Caller ID or schedule the call for later.", "Hit the 'Send Prank Call' button and let our system work its magic." ], "best_practices": "For maximum impact, keep scripts short, punchy, and to the point. Use voices that contrast with the message for extra humor (e.g., a 'Scary Deep Voice' ordering a tiny cupcake). Always ensure your prank is harmless and that the recipient will find it funny. This tool is for entertainment, not harassment." }, "structured_data": { "@context": "https://schema.org", "@type": "WebApplication", "name": "AI Prank Call Bot", "description": "Send hilarious, AI-powered prank calls with custom scripts and funny voices.", "url": "https://digitalprank.com/tools/ai-prank-caller", "applicationCategory": "EntertainmentApplication", "operatingSystem": "Any (Web-based)", "offers": { "@type": "Offer", "price": "0.00", "priceCurrency": "USD", "description": "Free tier with 2 daily calls." }, "softwareHelp": { "@type": "CreativeWork", "name": "AI Prank Call Bot Help & FAQ", "url": "https://ai-prank-caller.digitalprank.com/help.md" } } }``` ### FILE 7: /home/ai-prank-caller.digitalprank.com/public_html/deploy.sh ```bash #!/bin/bash # Deployment script for the AI Prank Call Bot tool # This script must be run with root privileges. set -e # --- Configuration --- TOOL_SLUG="ai-prank-caller" TOOL_DOMAIN="${TOOL_SLUG}.digitalprank.com" TOOL_ROOT="/home/${TOOL_DOMAIN}/public_html" VENV_PATH="/var/www/venv/${TOOL_SLUG}" DB_NAME='digitalprank_db' DB_USER='dp_user' DB_PASS='#$Dealer2355' WEB_USER='www-data' WEB_GROUP='www-data' echo "--- Starting deployment for ${TOOL_SLUG} ---" # 1. Install System Packages echo "[TASK 1/8] Installing system packages (ffmpeg, sox)..." apt-get update -y apt-get install -y ffmpeg sox python3-venv python3-pip # 2. Install PHP Extensions echo "[TASK 2/8] Ensuring PHP extensions are installed (curl, json, mbstring)..." # This step is highly dependent on the PHP setup. For many modern setups (e.g., Ondrej's PPA), # these extensions are often enabled by default or easily installed. # Example: apt-get install -y php8.1-curl php8.1-mbstring echo "Skipping automatic PHP extension installation. Please ensure curl, json, and mbstring are enabled." # 3. Create Python Virtual Environment and Install Packages echo "[TASK 3/8] Setting up Python virtual environment at ${VENV_PATH}..." if [ ! -d "${VENV_PATH}" ]; then mkdir -p /var/www/venv chown ${WEB_USER}:${WEB_GROUP} /var/www/venv python3 -m venv "${VENV_PATH}" echo "Created Python venv." fi echo "Activating venv and installing Python packages (xtts, pydub, twilio)..." source "${VENV_PATH}/bin/activate" pip install --upgrade pip pip install 'xtts-cli' pydub twilio deactivate chown -R ${WEB_USER}:${WEB_GROUP} "${VENV_PATH}" echo "Python packages installed." # 4. Create Tool-Specific Database Table echo "[TASK 4/8] Creating database table 'prank_call_history' if it doesn't exist..." SQL_CREATE_TABLE=" CREATE TABLE IF NOT EXISTS \`prank_call_history\` ( \`id\` BIGINT PRIMARY KEY AUTO_INCREMENT, \`user_id\` BIGINT NOT NULL, \`victim_phone\` VARCHAR(20) NOT NULL, \`caller_id\` VARCHAR(20), \`script\` TEXT, \`voice\` VARCHAR(50), \`audio_url\` VARCHAR(255), \`call_sid\` VARCHAR(40) UNIQUE, \`status\` VARCHAR(20) DEFAULT 'pending', \`schedule_time\` DATETIME NULL, \`created_at\` TIMESTAMP DEFAULT CURRENT_TIMESTAMP, \`updated_at\` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, INDEX \`user_id_idx\` (\`user_id\`), INDEX \`status_idx\` (\`status\`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; " mysql -hlocalhost -u"${DB_USER}" -p"${DB_PASS}" "${DB_NAME}" -e "${SQL_CREATE_TABLE}" echo "Database table schema ensured." # 5. Create Directories and Set Permissions echo "[TASK 5/8] Creating directories and setting permissions..." mkdir -p "${TOOL_ROOT}/uploads" # Assuming the tool's code has already been placed in TOOL_ROOT chown -R ${WEB_USER}:${WEB_GROUP} "/home/${TOOL_DOMAIN}" find "/home/${TOOL_DOMAIN}" -type d -exec chmod 755 {} \; find "/home/${TOOL_DOMAIN}" -type f -exec chmod 644 {} \; chmod 775 "${TOOL_ROOT}/uploads" echo "Directory structure and permissions set." # 6. Configure OpenLiteSpeed Virtual Host echo "[TASK 6/8] Generating OpenLiteSpeed virtual host config..." # This is a sample. Manual integration into /usr/local/lsws/conf/httpd_config.conf is required. OLS_VH_CONFIG_PATH="/usr/local/lsws/conf/vhosts/${TOOL_SLUG}" mkdir -p "${OLS_VH_CONFIG_PATH}" cat > "${OLS_VH_CONFIG_PATH}/vhost.conf" << EOL docRoot \$VH_ROOT vhDomain ${TOOL_DOMAIN} vhAliases www.${TOOL_DOMAIN} adminEmails webmaster@${TOOL_DOMAIN} enableGzip 1 errorlog \$SERVER_ROOT/logs/\$VH_NAME.error.log { logLevel ERROR rollingSize 10M } accesslog \$SERVER_ROOT/logs/\$VH_NAME.access.log { rollingSize 10M keepDays 10 compressArchive 1 } index { useServer 0 indexFiles index.php, index.html } scripthandler { add lsapi:php81 php } extprocessor php81 { type lsapi address uds://tmp/lshttpd/php81.sock maxConns 35 env LSAPI_CHILDREN=35 initTimeout 60 retryTimeout 0 persistConn 1 respBuffer 0 autoStart 1 path /usr/local/lsws/lsphp81/bin/lsphp backlog 100 instances 1 } rewrite { enable 1 autoLoadHtaccess 1 } EOL echo "Virtual host config created at ${OLS_VH_CONFIG_PATH}/vhost.conf" echo "ACTION REQUIRED: Add 'map ${TOOL_SLUG} ${TOOL_DOMAIN}' to your virtual host mappings in OpenLiteSpeed." # 7. Setup Log Rotation echo "[TASK 7/8] Setting up log rotation..." LOGROTATE_CONFIG="/etc/logrotate.d/${TOOL_SLUG}" cat > "${LOGROTATE_CONFIG}" << EOL /usr/local/lsws/logs/${TOOL_SLUG}.*.log { daily missingok rotate 14 compress delaycompress notifempty create 640 root adm sharedscripts postrotate /usr/local/lsws/bin/lswsctrl restart endscript } EOL echo "Log rotation configured at ${LOGROTATE_CONFIG}" # 8. Final Health Check Reminder echo "[TASK 8/8] Deployment tasks complete." echo "Please restart OpenLiteSpeed for changes to take effect: 'sudo /usr/local/lsws/bin/lswsctrl restart'" echo "To validate the installation, ensure DNS for '${TOOL_DOMAIN}' is pointing to this server, then access:" echo "http://${TOOL_DOMAIN}/diagnostic.php?key=digitalprank2025" echo "--- Deployment for ${TOOL_SLUG} finished! ---" Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 8: /home/ai-prank-caller.digitalprank.com/public_html/generate_audio.py code Python #!/var/www/venv/ai-prank-caller/bin/python # -*- coding: utf-8 -*- """ AI Prank Caller - Audio Generation Script Accepts text and a voice style, and generates a WAV audio file using XTTS. """ import argparse import os import sys import torch from TTS.api import TTS def generate_audio(text, voice_style, output_path): """ Generates an audio file from text using a specified voice. Args: text (str): The text to convert to speech. voice_style (str): The key for the voice model to use. Not directly used by XTTSv2 but could be used for speaker selection in the future. For now, we use a default speaker WAV. output_path (str): The path to save the generated WAV file. """ try: # Check for CUDA availability device = "cuda" if torch.cuda.is_available() else "cpu" print(f"INFO: Using device: {device}") # Initialize XTTSv2 model # This will download the model on the first run to a cache directory print("INFO: Initializing TTS model (XTTSv2)...") tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2", gpu=torch.cuda.is_available()) # Define a path to a reference speaker audio. # In a real application, you would have a library of speaker WAVs # mapped from the 'voice_style' input. # For now, we'll use a placeholder path. speaker_wav_path = "/var/www/assets/voices/default_speaker.wav" if not os.path.exists(speaker_wav_path): print(f"ERROR: Speaker WAV file not found at {speaker_wav_path}", file=sys.stderr) # As a fallback, we will let the model clone its own default voice if the file is missing. print("WARNING: Proceeding with default internal speaker.", file=sys.stderr) speaker_wav_path = None print(f"INFO: Generating audio for text: '{text[:50]}...'") # Synthesize speech tts.tts_to_file( text=text, speaker_wav=speaker_wav_path, # Path to a reference audio file to clone the voice from language="en", # Set language file_path=output_path ) print(f"SUCCESS: Audio file saved to {output_path}") except Exception as e: print(f"ERROR: An error occurred during audio generation: {e}", file=sys.stderr) sys.exit(1) if __name__ == "__main__": parser = argparse.ArgumentParser(description="Generate audio from text using XTTS.") parser.add_argument("--text", type=str, required=True, help="The text to synthesize.") parser.add_argument("--voice", type=str, required=True, help="The voice style to use (currently for reference).") parser.add_argument("--out", type=str, required=True, help="The output path for the WAV file.") args = parser.parse_args() # Basic input validation if len(args.text.strip()) < 5: print("ERROR: Text must be at least 5 characters long.", file=sys.stderr) sys.exit(1) if not args.out.endswith(".wav"): print("ERROR: Output path must end with .wav", file=sys.stderr) sys.exit(1) # Ensure the output directory exists output_dir = os.path.dirname(args.out) if not os.path.exists(output_dir): os.makedirs(output_dir, exist_ok=True) generate_audio(args.text, args.voice, args.out) FILE 9: /home/ai-prank-caller.digitalprank.com/public_html/twilio_handler.php code PHP '; echo ''; if ($audio_url) { // If a valid audio URL is provided, instruct Twilio to play it. // The verb will play an audio file over the call. echo '' . htmlspecialchars($audio_url) . ''; // After playing the file, we can add a brief pause. echo ''; } else { // If no valid audio URL is found, play an error message. // The verb uses Twilio's text-to-speech. echo 'An application error has occurred. Goodbye.'; } // The verb explicitly ends the call. // If omitted, the call would end automatically after the verb completes. echo ''; echo ''; // No further output should be sent. exit; Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 10: /home/ai-prank-caller.digitalprank.com/public_html/history.php code PHP setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { die("Could not connect to the database."); } // Pagination logic $page = isset($_GET['page']) ? (int)$_GET['page'] : 1; $limit = 15; $offset = ($page - 1) * $limit; // Fetch total count for pagination $count_stmt = $pdo->prepare("SELECT COUNT(*) FROM prank_call_history WHERE user_id = ?"); $count_stmt->execute([$user_id]); $total_records = $count_stmt->fetchColumn(); $total_pages = ceil($total_records / $limit); // Fetch records for the current page $stmt = $pdo->prepare( "SELECT victim_phone, status, script, audio_url, created_at FROM prank_call_history WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?" ); $stmt->execute([$user_id, $limit, $offset]); $history_records = $stmt->fetchAll(PDO::FETCH_ASSOC); ?> My Prank Call History

    My Prank Call History

    You haven't sent any prank calls yet.

    Date Sent To Script Status Recording
    50 ? '...' : ''); ?> N/A
    FILE 11: /home/ai-prank-caller.digitalprank.com/public_html/twilio_status_webhook.php code PHP validate($twilioSignature, $url, $postVars)) { header('HTTP/1.1 403 Forbidden'); error_log("Twilio Webhook: Invalid signature received."); exit("Invalid signature."); } // --- Process the Webhook Data --- header('Content-Type: text/plain'); $callSid = isset($_POST['CallSid']) ? $_POST['CallSid'] : null; $callStatus = isset($_POST['CallStatus']) ? $_POST['CallStatus'] : null; if (!$callSid || !$callStatus) { header("HTTP/1.1 400 Bad Request"); error_log("Twilio Webhook: Missing CallSid or CallStatus."); exit("Missing required parameters."); } // Log the incoming request for debugging $log_file = __DIR__ . '/webhook_log.txt'; $log_entry = "[" . date('Y-m-d H:i:s') . "] SID: $callSid, Status: $callStatus\n"; file_put_contents($log_file, $log_entry, FILE_APPEND); // Connect to the database $db_host = 'localhost'; $db_name = 'digitalprank_db'; $db_user = 'dp_user'; $db_pass = '#$Dealer2355'; try { $pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Update the record in the database $stmt = $pdo->prepare("UPDATE prank_call_history SET status = ? WHERE call_sid = ?"); $stmt->execute([$callStatus, $callSid]); if ($stmt->rowCount() > 0) { echo "Status for $callSid updated to $callStatus."; } else { // This might happen if Twilio sends a webhook for a SID not in our system. header("HTTP/1.1 404 Not Found"); error_log("Twilio Webhook: CallSid $callSid not found in the database."); echo "CallSid not found."; } } catch (PDOException $e) { header("HTTP/1.1 500 Internal Server Error"); error_log("Twilio Webhook: Database error - " . $e->getMessage()); echo "Database error."; } FILE 12: /home/ai-prank-caller.digitalprank.com/public_html/cron_scheduler.php code PHP #!/usr/bin/php setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Find scheduled calls that are due $stmt = $pdo->prepare( "SELECT id, victim_phone, caller_id, audio_url FROM prank_call_history WHERE status = 'scheduled' AND schedule_time <= NOW()" ); $stmt->execute(); $due_calls = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($due_calls)) { echo "No scheduled calls are due.\n"; } else { echo "Found " . count($due_calls) . " due calls to process.\n"; // In a real app, load Twilio SDK and credentials securely // require_once 'vendor/autoload.php'; // use Twilio\Rest\Client; // $twilio_client = new Client(getenv('TWILIO_SID'), getenv('TWILIO_TOKEN')); foreach ($due_calls as $call) { echo "Processing call ID: {$call['id']} to {$call['victim_phone']}...\n"; try { // Prepare TwiML URL for the call handler $handler_url = "https://ai-prank-caller.digitalprank.com/twilio_handler.php?audio_url=" . urlencode($call['audio_url']); // MOCK INITIATING TWILIO CALL // $twilio_call = $twilio_client->calls->create( // $call['victim_phone'], // $call['caller_id'], // The 'from' number // ['url' => $handler_url] // ); // $new_call_sid = $twilio_call->sid; // For this mock, generate a new SID $new_call_sid = 'CA_CRON_' . bin2hex(random_bytes(14)); $new_status = 'queued'; // Update the database with the new SID and status $update_stmt = $pdo->prepare( "UPDATE prank_call_history SET status = ?, call_sid = ? WHERE id = ?" ); $update_stmt->execute([$new_status, $new_call_sid, $call['id']]); echo " -> Successfully initiated call. New SID: {$new_call_sid}\n"; } catch (Exception $e) { // If initiating the call failed, update status to 'failed' $fail_stmt = $pdo->prepare( "UPDATE prank_call_history SET status = 'failed' WHERE id = ?" ); $fail_stmt->execute([$call['id']]); error_log("Scheduler Error: Failed to initiate call for ID {$call['id']}: " . $e->getMessage()); echo " -> ERROR: Failed to initiate call. See error log.\n"; } } } } catch (PDOException $e) { error_log("Scheduler Error: Database connection failed - " . $e->getMessage()); echo "ERROR: Database connection failed.\n"; } finally { // --- Release Lock --- flock($lock_handle, LOCK_UN); fclose($lock_handle); echo "Scheduler finished at " . date('Y-m-d H:i:s') . "\n"; } FILE 13: /home/ai-prank-caller.digitalprank.com/public_html/api.php code PHP false, 'message' => 'API key is missing.']); exit; } // Database Connection $db_host = 'localhost'; $db_name = 'digitalprank_db'; $db_user = 'dp_user'; $db_pass = '#$Dealer2355'; try { $pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'API service unavailable.']); exit; } // --- Validate API Key and Get User Info --- // In a real system, you'd have an `api_keys` table linked to `users`. // We will mock this by assuming a key maps to a user_id with Ultimate tier access. $stmt = $pdo->prepare("SELECT user_id FROM wp_user_api_keys WHERE api_key = ? AND is_active = 1"); // $stmt->execute([$api_key]); // $user_id = $stmt->fetchColumn(); $user_id = ($api_key === 'dp-ultimate-user-secret-key') ? 101 : false; // Mock validation if (!$user_id) { http_response_code(403); echo json_encode(['success' => false, 'message' => 'Invalid or inactive API key.']); exit; } // For API users, we assume they have 'ultimate' tier access. $access = ['tier' => 'ultimate', 'level' => 3]; // --- Process API Request --- if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['success' => false, 'message' => 'Method not allowed. Use POST.']); exit; } $input = json_decode(file_get_contents('php://input'), true); if (json_last_error() !== JSON_ERROR_NONE) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Invalid JSON body.']); exit; } // --- Input Validation (Simplified for API) --- $script = $input['script_prompt'] ?? null; $voice = $input['voice_style'] ?? 'annoying_robot'; $victim_phone = $input['victim_phone'] ?? null; $caller_id = $input['caller_id'] ?? null; // Optional $errors = []; if (empty($script) || strlen($script) < 10 || strlen($script) > 500) { $errors[] = 'script_prompt must be between 10 and 500 characters.'; } if (empty($victim_phone) || !preg_match('/^\+[1-9]\d{1,14}$/', $victim_phone)) { $errors[] = 'victim_phone is required and must be in E.164 format.'; } if (!empty($caller_id) && !preg_match('/^\+[1-9]\d{1,14}$/', $caller_id)) { $errors[] = 'caller_id must be in E.164 format if provided.'; } if (!empty($errors)) { http_response_code(422); // Unprocessable Entity echo json_encode(['success' => false, 'errors' => $errors]); exit; } // --- Core Logic (similar to processor.php) --- try { // 1. Generate Audio (mocked) $output_filename = 'api_prank_' . uniqid() . '.wav'; $audio_url = "https://cdn.digitalprank.com/audio/pranks/" . $output_filename; // 2. Initiate Call (mocked) $call_sid = 'CA_API_' . bin2hex(random_bytes(15)); $status = 'queued'; // 3. Store in Database $stmt = $pdo->prepare( "INSERT INTO prank_call_history (user_id, victim_phone, caller_id, script, voice, audio_url, call_sid, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" ); $stmt->execute([$user_id, $victim_phone, $caller_id, $script, $voice, $audio_url, $call_sid, $status]); // --- Success Response --- http_response_code(202); // Accepted echo json_encode([ 'success' => true, 'message' => 'Prank call accepted and is being processed.', 'call_sid' => $call_sid, 'status' => $status ]); } catch (Exception $e) { http_response_code(500); error_log("API Error: " . $e->getMessage()); echo json_encode(['success' => false, 'message' => 'An internal server error occurred while processing the request.']); } Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 14: /home/ai-prank-caller.digitalprank.com/public_html/admin/index.php code PHP Admin Login

    Tool Admin Login

    $login_error

    "; ?>

    setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { die("Database connection failed."); } // Get Tool ID $tool_slug = 'ai-prank-caller'; $stmt = $pdo->prepare("SELECT tool_id FROM wp_digitalprank_tools WHERE slug = ?"); $stmt->execute([$tool_slug]); $tool_id = $stmt->fetchColumn(); // Handle form submissions for overrides if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['field_id'])) { $field_id = $_POST['field_id']; $override_type = $_POST['override_type']; $tier_required = $_POST['tier_required'] ?? 'basic'; $is_active = isset($_POST['is_active']) ? 1 : 0; $stmt = $pdo->prepare( "INSERT INTO wp_digitalprank_tool_overrides (tool_id, field_id, tier_required, override_type, is_active) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE tier_required = VALUES(tier_required), override_type = VALUES(override_type), is_active = VALUES(is_active)" ); $stmt->execute([$tool_id, $field_id, $tier_required, $override_type, $is_active]); header("Location: " . $_SERVER['PHP_SELF']); // Refresh page exit; } // Fetch current overrides $stmt = $pdo->prepare("SELECT field_id, tier_required, override_type, is_active FROM wp_digitalprank_tool_overrides WHERE tool_id = ?"); $stmt->execute([$tool_id]); $overrides = $stmt->fetchAll(PDO::FETCH_KEY_PAIR | PDO::FETCH_GROUP); // Fetch recent usage logs $usage_logs = $pdo->query("SELECT timestamp, user_id, ip_address, status, input_data FROM wp_digitalprank_usage_log WHERE tool_slug = '{$tool_slug}' ORDER BY timestamp DESC LIMIT 20")->fetchAll(PDO::FETCH_ASSOC); // Load tool config to get field list $config = json_decode(file_get_contents(__DIR__ . '/../tool_config.json'), true)['tool']; ?> Admin - AI Prank Caller

    Admin Panel: AI Prank Caller

    Field Overrides

    Control feature access for different subscription tiers.

    Field IDCurrent SettingAction
    " . htmlspecialchars($o['override_type']) . ", "; if($o['override_type'] == 'tier') echo "Tier: " . htmlspecialchars($o['tier_required']) . ", "; echo "Status: " . ($o['is_active'] ? 'Active' : 'Inactive'); } else { echo "Default (from JSON)"; } ?>

    Recent Usage (Last 20)

    TimeUser IDIPStatusInput
    ...
    ``` ### FILE 15: /home/ai-prank-caller.digitalprank.com/public_html/upgrade_prompt.php ```php

    Unlock Pro Features!

    Upgrade your account to access powerful features:

    Upgrade Now
    FILE 16: /home/ai-prank-caller.digitalprank.com/public_html/README.md```markdown AI Prank Caller Tool - Developer README This document provides technical setup and configuration instructions for the AI Prank Caller tool on the DigitalPrank platform. 1. Overview This tool allows users to send AI-voiced prank calls. It consists of a frontend form (tool_form.php), a backend processor (processor.php), an audio generation script (generate_audio.py), and several supporting scripts for handling webhooks, scheduling, and administration. 2. Dependencies Ensure all dependencies listed in tool_config.json are installed. The deploy.sh script automates most of this. System Packages: ffmpeg, sox, python3-venv PHP Extensions: curl, json, mbstring, pdo_mysql Python Venv (/var/www/venv/ai-prank-caller): xtts-cli, pydub, twilio PHP Composer: twilio/sdk (Install via composer require twilio/sdk in the public_html directory). 3. Configuration 3.1. Environment Variables The application relies on environment variables for security. These should be set in your web server's configuration (e.g., OpenLiteSpeed vHost config or a .env file loaded by your framework). TWILIO_ACCOUNT_SID: Your Twilio Account SID. TWILIO_AUTH_TOKEN: Your Twilio Auth Token. DEFAULT_TWILIO_NUMBER: A verified Twilio phone number to use as the default caller ID. 3.2. Web Server Configuration (OpenLiteSpeed) The deploy.sh script generates a sample vHost configuration. This must be manually added to your OpenLiteSpeed server configuration. The key parts are: Defining the virtualHost with the correct vhRoot. Mapping the domain ai-prank-caller.digitalprank.com to this virtual host. Ensuring the lsapi:php81 script handler is correctly configured. 3.3. Speaker Voice WAV The generate_audio.py script uses a reference audio file to clone a voice. Place a high-quality, 10-15 second WAV file of your desired default speaker at: /var/www/assets/voices/default_speaker.wav 4. Cron Jobs Two cron jobs are required for the tool's operation. Add the following lines to your system's crontab (crontab -e): code Crontab # Run the prank call scheduler every minute to process due calls * * * * * /usr/bin/php /home/ai-prank-caller.digitalprank.com/public_html/cron_scheduler.php >> /var/log/digitalprank/scheduler.log 2>&1 # Run the data cleanup job once per day at 3:00 AM 0 3 * * * /usr/bin/php /home/ai-prank-caller.digitalprank.com/public_html/cleanup.php >> /var/log/digitalprank/cleanup.log 2>&1 Ensure the log directory /var/log/digitalprank/ exists and is writable by the cron user. 5. Twilio Webhook Configuration Twilio needs to send real-time updates about the call's status. In your Twilio phone number's configuration: A CALL COMES IN: Set to Webhook. URL: https://ai-prank-caller.digitalprank.com/twilio_status_webhook.php HTTP Method: HTTP POST Under the main "Voice" settings for your account, find the "Status Callbacks" section and set the URL to the same webhook to receive final call status updates. 6. API Usage The API provides programmatic access to the tool. Endpoint: https://ai-prank-caller.digitalprank.com/api.php Method: POST Authentication: Provide your API key in the X-API-KEY header. Body: JSON payload. Example Request: code Bash curl -X POST \ https://ai-prank-caller.digitalprank.com/api.php \ -H 'Content-Type: application/json' \ -H 'X-API-KEY: dp-ultimate-user-secret-key' \ -d '{ "script_prompt": "Hello, we have been trying to reach you about your car'\''s extended warranty.", "voice_style": "slick_salesman", "victim_phone": "+15551234567", "caller_id": "+15558675309" }' Success Response (202 Accepted): code JSON { "success": true, "message": "Prank call accepted and is being processed.", "call_sid": "CA_API_...", "status": "queued" } code Code ### FILE 17: /home/ai-prank-caller.digitalprank.com/public_html/rate_limiter.php ```php pdo = $pdo; $this->tool_slug = $config['identity']['slug']; $this->rate_limit_per_minute = $config['limits']['rate_limit_per_minute']; $this->max_concurrent_requests = $config['limits']['max_concurrent_requests']; } /** * Checks if the user is allowed to make a request based on per-minute limits. * * @param string $user_identifier (IP address or User ID) * @return bool True if allowed, false if rate-limited. */ public function isAllowed(string $user_identifier): bool { // We use the usage log table for rate limiting. // This is simple but might be slow under heavy load. Redis would be better. $stmt = $this->pdo->prepare( "SELECT COUNT(*) FROM wp_digitalprank_usage_log WHERE (ip_address = ? OR user_id = ?) AND tool_slug = ? AND timestamp > (NOW() - INTERVAL 1 MINUTE)" ); $stmt->execute([$user_identifier, (int)$user_identifier, $this->tool_slug]); $request_count = $stmt->fetchColumn(); return $request_count < $this->rate_limit_per_minute; } /** * Checks for concurrent requests. * This is a simplified check and may not be perfectly accurate without a proper locking mechanism. * * @param int $user_id * @return bool True if under the concurrency limit, false otherwise. */ public function checkConcurrency(int $user_id): bool { if ($user_id === 0) { // Concurrency checks are for logged-in users only return true; } $stmt = $this->pdo->prepare( "SELECT COUNT(*) FROM wp_digitalprank_usage_log WHERE user_id = ? AND tool_slug = ? AND status = 'processing' -- A custom status you'd have to manage AND timestamp > (NOW() - INTERVAL 5 MINUTE)" ); $stmt->execute([$user_id, $this->tool_slug]); $concurrent_requests = $stmt->fetchColumn(); return $concurrent_requests < $this->max_concurrent_requests; } } ?> FILE 18: /home/ai-prank-caller.digitalprank.com/public_html/cleanup.php code PHP #!/usr/bin/php setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { error_log("Cleanup Cron: Database connection failed: " . $e->getMessage()); die("Database connection failed.\n"); } // --- Load all tool configs to find their retention policies --- $tools_dir = '/home/digitalprank.com/public_html/tools/'; // A hypothetical directory $tool_slugs = ['ai-prank-caller']; // In a real system, you'd scan for all tools foreach ($tool_slugs as $slug) { $config_path = "/home/{$slug}.digitalprank.com/public_html/tool_config.json"; if (!file_exists($config_path)) { echo "Config for '{$slug}' not found. Skipping.\n"; continue; } $config = json_decode(file_get_contents($config_path), true)['tool']; $db_config = $config['database'] ?? null; if ($db_config && $db_config['store_results'] && !empty($db_config['tool_specific_table']) && !empty($db_config['retention_days'])) { $table_name = $db_config['tool_specific_table']; $retention_days = (int)$db_config['retention_days']; if ($retention_days > 0) { echo "Processing table '{$table_name}' with a {$retention_days}-day retention policy...\n"; try { $sql = "DELETE FROM `{$table_name}` WHERE `created_at` < (NOW() - INTERVAL {$retention_days} DAY)"; $stmt = $pdo->prepare($sql); $stmt->execute(); $deleted_count = $stmt->rowCount(); echo " -> Deleted {$deleted_count} old records from `{$table_name}`.\n"; } catch (Exception $e) { error_log("Cleanup Cron: Error cleaning table '{$table_name}': " . $e->getMessage()); echo " -> ERROR processing table '{$table_name}'. See logs.\n"; } } } } // --- Clean up the main usage log table (e.g., keep 90 days of logs) --- $general_log_retention_days = 90; echo "Processing platform-wide 'wp_digitalprank_usage_log' with a {$general_log_retention_days}-day policy...\n"; try { $sql = "DELETE FROM `wp_digitalprank_usage_log` WHERE `timestamp` < (NOW() - INTERVAL {$general_log_retention_days} DAY)"; $stmt = $pdo->prepare($sql); $stmt->execute(); $deleted_count = $stmt->rowCount(); echo " -> Deleted {$deleted_count} old records from `wp_digitalprank_usage_log`.\n"; } catch (Exception $e) { error_log("Cleanup Cron: Error cleaning 'wp_digitalprank_usage_log': " . $e->getMessage()); echo " -> ERROR processing 'wp_digitalprank_usage_log'. See logs.\n"; } echo "Data cleanup job finished at " . date('Y-m-d H:i:s') . "\n"; Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 19: /home/ai-prank-caller.digitalprank.com/public_html/assets/js/main.js code JavaScript /** * Main JavaScript file for the AI Prank Caller Tool * Handles form submissions, UI updates, and conditional logic. */ document.addEventListener('DOMContentLoaded', function() { const toolForm = document.getElementById('toolForm'); if (!toolForm) { console.error("Tool form not found. Aborting script."); return; } const loadingOverlay = document.getElementById('loadingOverlay'); const resultModal = document.getElementById('resultModal'); const resultTitle = document.getElementById('resultTitle'); const resultBody = document.getElementById('resultBody'); const closeModalButton = document.getElementById('closeModal'); const useAiVoiceCheckbox = document.getElementById('use_ai_voice'); const customAudioGroup = document.getElementById('group_custom_audio_file'); const scriptPromptGroup = document.getElementById('group_script_prompt'); const victimPhoneField = document.getElementById('victim_phone'); // This value should be set by PHP based on the user's logged-in status and tier. const userAccess = { hasPro: document.body.dataset.hasProAccess === 'true' || false }; /** * Toggles the visibility of the script prompt and the custom audio upload field * based on the state of the "Use AI Voice" checkbox. */ function toggleInputFields() { if (!useAiVoiceCheckbox) return; if (useAiVoiceCheckbox.checked) { if (scriptPromptGroup) scriptPromptGroup.style.display = 'block'; if (customAudioGroup) customAudioGroup.style.display = 'none'; } else { if (scriptPromptGroup) scriptPromptGroup.style.display = 'none'; // Only show the custom audio field if the user is a Pro member if (customAudioGroup && userAccess.hasPro) { customAudioGroup.style.display = 'block'; } } } /** * Handles the form submission via AJAX. * @param {Event} e The form submission event. */ function handleFormSubmit(e) { e.preventDefault(); // Perform client-side validation if (!toolForm.checkValidity()) { toolForm.reportValidity(); return; } // Additional validation for Pro features if (!userAccess.hasPro && victimPhoneField && victimPhoneField.value) { displayModal('Error', "Sending calls is a Pro feature. Please upgrade your account to continue.", true); return; } if (loadingOverlay) loadingOverlay.style.display = 'flex'; const formData = new FormData(toolForm); // Ensure checkbox value is correctly represented when unchecked if (useAiVoiceCheckbox && !useAiVoiceCheckbox.checked) { formData.set('use_ai_voice', '0'); } fetch('processor.php', { method: 'POST', body: formData }) .then(response => { if (!response.ok) { // Handle non-2xx responses by trying to parse the JSON error message return response.json().then(err => Promise.reject(err)); } return response.json(); }) .then(data => { if (data.success) { displayModal('Success!', data.data.message || 'Your prank call has been queued successfully.'); toolForm.reset(); // Clear the form on success } else { displayModal('Error', data.message || 'An unknown error occurred.', true); } }) .catch(error => { console.error('Submission Error:', error); const errorMessage = error.message || 'A network error occurred. Please check your connection and try again.'; displayModal('Submission Failed', errorMessage, true); }) .finally(() => { if (loadingOverlay) loadingOverlay.style.display = 'none'; }); } /** * Displays the result modal with a given title and body. * @param {string} title The title to display. * @param {string} bodyHTML The HTML content for the modal body. * @param {boolean} isError If true, styles the title as an error. */ function displayModal(title, bodyHTML, isError = false) { if (!resultModal) return; if (resultTitle) { resultTitle.textContent = title; resultTitle.className = isError ? 'error-message' : 'success-message'; } if (resultBody) { resultBody.innerHTML = bodyHTML; } resultModal.style.display = 'flex'; } /** * Hides the result modal. */ function hideModal() { if (resultModal) resultModal.style.display = 'none'; } // --- Event Listeners --- if (useAiVoiceCheckbox) { useAiVoiceCheckbox.addEventListener('change', toggleInputFields); } toolForm.addEventListener('submit', handleFormSubmit); if (closeModalButton) { closeModalButton.addEventListener('click', hideModal); } if (resultModal) { // Close modal if user clicks outside the content area resultModal.addEventListener('click', (event) => { if (event.target === resultModal) { hideModal(); } }); } // --- Initial State Setup --- toggleInputFields(); }); FILE 20: /home/ai-prank-caller.digitalprank.com/public_html/assets/css/style.css code CSS /** * Main Stylesheet for the AI Prank Caller Tool */ /* --- General & Variables --- */ :root { --primary-color: #FF4500; /* OrangeRed */ --secondary-color: #1a1a1a; --background-color: #f4f7f6; --form-background: #ffffff; --border-color: #d1d1d1; --success-color: #28a745; --error-color: #dc3545; --text-color: #333; --label-color: #555; --help-text-color: #777; } body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; background-color: var(--background-color); color: var(--text-color); margin: 0; padding: 20px; } /* --- Form Container --- */ #toolForm { max-width: 650px; margin: 2rem auto; padding: 2rem; background: var(--form-background); border-radius: 12px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08); border: 1px solid var(--border-color); } .form-group { margin-bottom: 1.5rem; } label { display: block; margin-bottom: 0.5rem; font-weight: 600; color: var(--label-color); font-size: 0.95rem; } .form-control { width: 100%; padding: 0.8rem 1rem; border: 1px solid var(--border-color); border-radius: 8px; box-sizing: border-box; transition: border-color 0.2s, box-shadow 0.2s; font-size: 1rem; } .form-control:focus { border-color: var(--primary-color); box-shadow: 0 0 0 3px rgba(255, 69, 0, 0.2); outline: none; } textarea.form-control { min-height: 140px; resize: vertical; } /* --- Pro & Disabled States --- */ .pro-badge { background-color: #ffd700; color: #333; font-size: 0.65rem; padding: 3px 7px; border-radius: 10px; margin-left: 8px; font-weight: bold; vertical-align: middle; letter-spacing: 0.5px; } .field-disabled { opacity: 0.65; cursor: not-allowed; } .field-disabled label, .field-disabled .form-control { cursor: not-allowed; } .field-disabled .form-control { background-color: #f9f9f9; } .help-text { font-size: 0.8rem; color: var(--help-text-color); margin-top: 6px; } /* --- Buttons --- */ .submit-btn { background: var(--primary-color); background: linear-gradient(145deg, var(--primary-color), #f97316); color: white; padding: 14px 24px; border: none; border-radius: 8px; cursor: pointer; font-size: 1.1rem; font-weight: 600; width: 100%; transition: transform 0.1s, box-shadow 0.2s; } .submit-btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(255, 69, 0, 0.3); } /* --- Checkbox Styling --- */ .checkbox-label { display: flex; align-items: center; font-weight: normal; cursor: pointer; } .checkbox-label input[type="checkbox"] { margin-right: 12px; height: 1.2em; width: 1.2em; accent-color: var(--primary-color); } /* --- Overlays and Modals --- */ .loading-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.85); backdrop-filter: blur(4px); z-index: 10000; display: none; justify-content: center; align-items: center; flex-direction: column; gap: 1rem; } .spinner { border: 5px solid #f3f3f3; border-top: 5px solid var(--primary-color); border-radius: 50%; width: 50px; height: 50px; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .modal { position: fixed; z-index: 10001; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgba(0, 0, 0, 0.6); backdrop-filter: blur(5px); display: none; align-items: center; justify-content: center; } .modal-content { background-color: var(--form-background); margin: auto; padding: 2rem 2.5rem; border: none; width: 90%; max-width: 500px; border-radius: 12px; text-align: center; position: relative; animation: fadeIn 0.3s ease-out; } @keyframes fadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } } .close-button { color: #aaa; position: absolute; top: 10px; right: 20px; font-size: 32px; font-weight: bold; cursor: pointer; transition: color 0.2s; } .close-button:hover { color: #333; } .error-message { color: var(--error-color); } .success-message { color: var(--success-color); } Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 21: /home/ai-prank-caller.digitalprank.com/public_html/index.php code PHP <?php echo htmlspecialchars($config['seo']['meta_title']); ?>

    FILE 22: /home/ai-prank-caller.digitalprank.com/public_html/composer.json code JSON { "name": "digitalprank/ai-prank-caller", "description": "The backend services for the AI Prank Caller tool.", "type": "project", "require": { "php": ">=8.1", "twilio/sdk": "^7.0" }, "authors": [ { "name": "DigitalPrank Dev Team", "email": "dev@digitalprank.com" } ], "config": { "vendor-dir": "vendor" }, "minimum-stability": "stable" } FILE 23: /home/ai-prank-caller.digitalprank.com/public_html/processor.php code PHP setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'Database connection failed.']); exit; } // --- Configuration & Session --- $config = json_decode(file_get_contents(__DIR__ . '/tool_config.json'), true)['tool']; session_start(); $user_id = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : 0; $user_ip = $_SERVER['REMOTE_ADDR']; // --- CSRF Check --- if ($_SERVER['REQUEST_METHOD'] === 'POST') { if (empty($_POST['csrf_token']) || empty($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { http_response_code(403); echo json_encode(['success' => false, 'message' => 'Invalid session token. Please refresh and try again.']); exit; } } $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); // Regenerate for next request // --- Rate Limiting --- $rate_limiter = new RateLimiter($pdo, $config); $user_identifier = $user_id > 0 ? (string)$user_id : $user_ip; if (!$rate_limiter->isAllowed($user_identifier)) { http_response_code(429); // Too Many Requests echo json_encode(['success' => false, 'message' => 'You are making requests too quickly. Please wait a moment.']); exit; } // --- User Access & Usage Check --- $access = getUserAccessLevel($pdo, $user_id, $config['identity']['slug']); $limit = $config['limits']['tier_daily'][$access['tier']]; if (!checkDailyUsage($pdo, $config['identity']['slug'], $user_ip, $user_id, $limit)) { http_response_code(429); echo json_encode(['success' => false, 'message' => 'You have exceeded your daily usage limit.']); exit; } // --- Main Processing Logic --- $input = $_POST; $start_time = microtime(true); $response = ['success' => false, 'data' => null]; try { // [The validation logic from the previous version of processor.php remains the same] $errors = []; $validated_input = []; $fields = $config['fields']; foreach ($fields as $field) { /* ... validation logic ... */ } if (!empty($errors)) { throw new Exception(implode(' ', $errors)); } // --- Tool Functionality --- $output_data = []; $audio_url_for_call = null; $use_ai_voice = !(isset($input['use_ai_voice']) && $input['use_ai_voice'] === '0'); if ($use_ai_voice) { // Mocked XTTS call $script_to_run = escapeshellarg($validated_input['script_prompt']); $output_filename = 'prank_' . uniqid() . '.wav'; $output_path = '/tmp/' . $output_filename; // shell_exec("/var/www/venv/ai-prank-caller/bin/python generate_audio.py --text {$script_to_run} --voice ... --out {$output_path}"); $audio_url_for_call = "https://cdn.digitalprank.com/audio/pranks/{$output_filename}"; $output_data['audio_generation_status'] = 'success'; } else { // Custom audio upload logic // [Logic for handling $_FILES['custom_audio_file'] remains the same] $public_filename = basename($custom_audio_path); $audio_url_for_call = "https://ai-prank-caller.digitalprank.com/uploads/{$public_filename}"; } // --- Twilio Call Initiation --- $twilio_client = new Client(getenv('TWILIO_ACCOUNT_SID'), getenv('TWILIO_AUTH_TOKEN')); $caller_id_to_use = getenv('DEFAULT_TWILIO_NUMBER'); if ($access['level'] >= getTierLevel('gold') && !empty($validated_input['caller_id'])) { $caller_id_to_use = $validated_input['caller_id']; } $handler_url = "https://ai-prank-caller.digitalprank.com/twilio_handler.php?audio_url=" . urlencode($audio_url_for_call); $call_options = [ 'from' => $caller_id_to_use, 'url' => $handler_url, 'statusCallback' => 'https://ai-prank-caller.digitalprank.com/twilio_status_webhook.php', 'statusCallbackMethod' => 'POST', 'statusCallbackEvent' => ['initiated', 'ringing', 'answered', 'completed'], ]; $call = $twilio_client->calls->create($validated_input['victim_phone'], $caller_id_to_use, $call_options); $output_data['call_sid'] = $call->sid; $output_data['call_status'] = $call->status; $output_data['message'] = "Prank call successfully initiated to {$validated_input['victim_phone']}."; // --- Database Logging --- if ($config['database']['store_results']) { $stmt = $pdo->prepare( "INSERT INTO prank_call_history (user_id, victim_phone, caller_id, script, voice, audio_url, call_sid, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)" ); $stmt->execute([ $user_id, $validated_input['victim_phone'], $caller_id_to_use, $validated_input['script_prompt'], $validated_input['voice_style'], $audio_url_for_call, $call->sid, $call->status ]); } $response['success'] = true; $response['data'] = $output_data; $processing_time = microtime(true) - $start_time; logUsage($pdo, $config['identity']['slug'], $user_ip, $user_id, 'success', $input, $output_data, $processing_time, $config['billing']['credit_cost']); } catch (Exception $e) { http_response_code(400); $response['message'] = $e->getMessage(); $processing_time = microtime(true) - $start_time; logUsage($pdo, $config['identity']['slug'], $user_ip, $user_id, 'failed', $input, ['error' => $e->getMessage()], $processing_time, 0); } // --- Final Response --- echo json_encode($response); // Helper functions (getToolOverrides, getTierLevel) remain the same function getTierLevel($tier_name) { $levels = ['free' => 0, 'basic' => 1, 'gold' => 2, 'ultimate' => 3]; return $levels[strtolower($tier_name)] ?? 0; } FILE 24: /home/ai-prank-caller.digitalprank.com/public_html/api.php code PHP false, 'message' => 'API key is missing.']); exit; } // --- Database Connection --- $db_host = 'localhost'; $db_name = 'digitalprank_db'; $db_user = 'dp_user'; $db_pass = '#$Dealer2355'; try { $pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'API service unavailable.']); exit; } // --- Validate API Key and User --- // In a real system, you would join tables to get user tier. $stmt = $pdo->prepare("SELECT user_id FROM wp_user_api_keys WHERE api_key = ? AND is_active = 1"); $stmt->execute([$api_key]); $user_id = $stmt->fetchColumn(); if (!$user_id) { http_response_code(403); echo json_encode(['success' => false, 'message' => 'Invalid or inactive API key.']); exit; } $config = json_decode(file_get_contents(__DIR__ . '/tool_config.json'), true)['tool']; // --- Rate Limiting for the API key/user --- $rate_limiter = new RateLimiter($pdo, $config); if (!$rate_limiter->isAllowed((string)$user_id)) { http_response_code(429); echo json_encode(['success' => false, 'message' => 'API rate limit exceeded.']); exit; } // --- Process API Request --- if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_encode(['success' => false, 'message' => 'Method not allowed. Use POST.']); exit; } $input = json_decode(file_get_contents('php://input'), true); if (json_last_error() !== JSON_ERROR_NONE) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Invalid JSON body.']); exit; } // --- Input Validation (Same as before) --- $script = $input['script_prompt'] ?? null; $victim_phone = $input['victim_phone'] ?? null; $errors = []; if (empty($script) || strlen($script) < 10 || strlen($script) > 500) $errors[] = 'script_prompt is required (10-500 chars).'; if (empty($victim_phone) || !preg_match('/^\+[1-9]\d{1,14}$/', $victim_phone)) $errors[] = 'victim_phone is required and must be in E.164 format.'; if (!empty($errors)) { http_response_code(422); echo json_encode(['success' => false, 'errors' => $errors]); exit; } // --- Core Logic --- try { // 1. Generate Audio (mocked) $audio_url = "https://cdn.digitalprank.com/audio/pranks/api_" . uniqid() . ".wav"; // 2. Initiate Twilio Call $twilio_client = new Client(getenv('TWILIO_ACCOUNT_SID'), getenv('TWILIO_AUTH_TOKEN')); $caller_id = $input['caller_id'] ?? getenv('DEFAULT_TWILIO_NUMBER'); $handler_url = "https://ai-prank-caller.digitalprank.com/twilio_handler.php?audio_url=" . urlencode($audio_url); $call = $twilio_client->calls->create($victim_phone, $caller_id, [ 'url' => $handler_url, 'statusCallback' => 'https://ai-prank-caller.digitalprank.com/twilio_status_webhook.php', 'statusCallbackMethod' => 'POST' ]); // 3. Log to Database $stmt = $pdo->prepare("INSERT INTO prank_call_history (user_id, victim_phone, caller_id, script, voice, audio_url, call_sid, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"); $stmt->execute([$user_id, $victim_phone, $caller_id, $script, $input['voice_style'] ?? 'annoying_robot', $audio_url, $call->sid, $call->status]); // --- Success Response --- http_response_code(202); echo json_encode(['success' => true, 'message' => 'Prank call accepted.', 'call_sid' => $call->sid, 'status' => $call->status]); } catch (Exception $e) { http_response_code(500); error_log("API Error for user {$user_id}: " . $e->getMessage()); echo json_encode(['success' => false, 'message' => 'An internal server error occurred.']); } Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 25: /home/ai-prank-caller.digitalprank.com/public_html/bootstrap.php code PHP get(); } catch (Exception $e) { // In a real app, you'd show a user-friendly error page. die("Fatal Error: Could not load or parse tool configuration: " . $e->getMessage()); } // --- Database Connection --- $db_host = 'localhost'; $db_name = 'digitalprank_db'; $db_user = 'dp_user'; $db_pass = '#$Dealer2355'; $pdo = null; // Make it globally accessible for scripts that include this bootstrap try { $pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]); } catch (PDOException $e) { // In a real API, you'd just log this and return a generic 500. die("Fatal Error: Database connection failed. Please check the service status."); } // --- Session Initialization --- session_start([ 'cookie_httponly' => true, 'cookie_secure' => isset($_SERVER['HTTPS']), 'cookie_samesite' => 'Lax' ]); // --- Service Initialization --- // Initialize services that might be needed by the including script. $twilioService = null; try { $twilioService = new TwilioService( getenv('TWILIO_ACCOUNT_SID'), getenv('TWILIO_AUTH_TOKEN'), getenv('DEFAULT_TWILIO_NUMBER') ); } catch (Exception $e) { // Log the error but don't die, as not all pages might need Twilio. error_log('Twilio Service Initialization Failed: ' . $e->getMessage()); } $rateLimiter = new RateLimiter($pdo, $config); // --- User Context --- $user_id = isset($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : 0; $user_ip = $_SERVER['REMOTE_ADDR']; // $access = getUserAccessLevel($pdo, $user_id, TOOL_SLUG); // This function would be defined in the platform includes FILE 26: /home/ai-prank-caller.digitalprank.com/public_html/services/TwilioService.php code PHP client = new Client($accountSid, $authToken); $this->authToken = $authToken; $this->defaultFromNumber = $defaultFromNumber; } /** * Initiates a call via Twilio. * * @param string $to The recipient's phone number in E.164 format. * @param string $audioUrl The publicly accessible URL of the audio file to play. * @param string|null $from The caller ID to use. If null, uses the default. * @return \Twilio\Rest\Api\V2010\Account\CallInstance * @throws \Twilio\Exceptions\TwilioException */ public function makeCall(string $to, string $audioUrl, ?string $from = null): \Twilio\Rest\Api\V2010\Account\CallInstance { $fromNumber = $from ?: $this->defaultFromNumber; // Construct the URL to our TwiML handler script $handlerUrl = "https://ai-prank-caller.digitalprank.com/twilio_handler.php?audio_url=" . urlencode($audioUrl); // Configure webhook for status updates $statusCallbackUrl = "https://ai-prank-caller.digitalprank.com/twilio_status_webhook.php"; return $this->client->calls->create( $to, $fromNumber, [ 'url' => $handlerUrl, 'statusCallback' => $statusCallbackUrl, 'statusCallbackMethod' => 'POST', 'statusCallbackEvent' => ['ringing', 'answered', 'completed', 'busy', 'failed', 'no-answer'], ] ); } /** * Validates an incoming webhook request to ensure it came from Twilio. * * @param string $signature The value of the X-Twilio-Signature header. * @param string $url The full URL of the request. * @param array $postVars The POST variables of the request. * @return bool True if the request is valid, false otherwise. */ public function validateRequest(string $signature, string $url, array $postVars): bool { $validator = new RequestValidator($this->authToken); return $validator->validate($signature, $url, $postVars); } } FILE 27: /home/ai-prank-caller.digitalprank.com/public_html/lib/Config.php code PHP settings = json_decode($jsonContent, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception("Error parsing configuration JSON: " . json_last_error_msg()); } } /** * Gets the single instance of the Config class. * @param string|null $configFilePath The path to the config file on first call. * @return Config * @throws Exception if the instance is requested without a file path for the first time. */ public static function getInstance(?string $configFilePath = null): Config { if (self::$instance === null) { if ($configFilePath === null) { throw new Exception("Configuration file path must be provided on first call to getInstance."); } self::$instance = new Config($configFilePath); } return self::$instance; } /** * Returns the entire configuration array. * @return array */ public function get(): array { return $this->settings['tool'] ?? []; } /** * Gets a specific configuration value using dot notation. * Example: 'identity.slug' * * @param string $key * @param mixed|null $default * @return mixed */ public function getVal(string $key, mixed $default = null): mixed { $config = $this->get(); $keys = explode('.', $key); $value = $config; foreach ($keys as $k) { if (!isset($value[$k])) { return $default; } $value = $value[$k]; } return $value; } } FILE 28: /home/ai-prank-caller.digitalprank.com/public_html/.htaccess code Apache # AI Prank Caller .htaccess File # Provides URL rewriting, security, and performance enhancements. RewriteEngine On # Redirect www to non-www (and https) RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC] RewriteRule ^(.*)$ https://%1/$1 [R=301,L] RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # Block access to sensitive files Require all denied # Block access to specific directories RewriteRule ^(vendor|database|services|lib)/ - [F,L] # Basic Front Controller: Route all non-existent file/dir requests to index.php # This is less critical for this simple tool but good practice. # RewriteCond %{REQUEST_FILENAME} !-f # RewriteCond %{REQUEST_FILENAME} !-d # RewriteRule . index.php [L] # Caching for static assets ExpiresActive On ExpiresByType image/jpeg "access plus 1 year" ExpiresByType image/png "access plus 1 year" ExpiresByType image/gif "access plus 1 year" ExpiresByType image/svg+xml "access plus 1 year" ExpiresByType text/css "access plus 1 month" ExpiresByType application/javascript "access plus 1 month" # Security Headers Header set X-Content-Type-Options "nosniff" Header set X-Frame-Options "SAMEORIGIN" Header set X-XSS-Protection "1; mode=block" # Header set Content-Security-Policy "default-src 'self';" # Disable directory browsing Options -Indexes # PHP settings php_flag log_errors On php_value error_log /home/ai-prank-caller.digitalprank.com/logs/php_errors.log FILE 29: /home/ai-prank-caller.digitalprank.com/public_html/database/schema.sql code SQL -- DigitalPrank Platform Schema for AI Prank Caller Tool -- This file documents the structure of the tool-specific table. -- The core platform tables (wp_digitalprank_*) are assumed to exist. -- Table structure for `prank_call_history` -- Stores a record for every prank call initiated by the tool. CREATE TABLE IF NOT EXISTS `prank_call_history` ( `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, `user_id` BIGINT UNSIGNED NOT NULL COMMENT 'Corresponds to the user ID in the main platform.', `victim_phone` VARCHAR(20) NOT NULL COMMENT 'The recipient''s phone number in E.164 format.', `caller_id` VARCHAR(20) DEFAULT NULL COMMENT 'The number displayed as the caller ID (From number).', `script` TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'The text script used for AI voice generation.', `voice` VARCHAR(50) DEFAULT NULL COMMENT 'The selected voice style, e.g., ''annoying_robot''.', `audio_url` VARCHAR(255) DEFAULT NULL COMMENT 'The public URL of the audio file played during the call.', `call_sid` VARCHAR(40) CHARACTER SET 'ascii' COLLATE 'ascii_general_ci' DEFAULT NULL COMMENT 'The unique session identifier from Twilio.', `status` VARCHAR(20) DEFAULT 'pending' COMMENT 'The status of the call, updated via Twilio webhook (e.g., queued, ringing, completed, failed).', `schedule_time` DATETIME DEFAULT NULL COMMENT 'If the call was scheduled, this is the time it was set for.', `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `call_sid` (`call_sid`), KEY `user_id_idx` (`user_id`), KEY `status_idx` (`status`), KEY `schedule_time_status_idx` (`schedule_time`, `status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='History of all prank calls made with the AI tool.'; -- Table structure for `wp_user_api_keys` (Assumed to exist for API) -- CREATE TABLE IF NOT EXISTS `wp_user_api_keys` ( -- `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, -- `user_id` BIGINT UNSIGNED NOT NULL, -- `api_key` VARCHAR(64) NOT NULL, -- `is_active` TINYINT(1) NOT NULL DEFAULT '1', -- `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- PRIMARY KEY (`id`), -- UNIQUE KEY `api_key` (`api_key`), -- KEY `user_id` (`user_id`) -- ) ENGINE=InnoDB; FILE 30: /home/ai-prank-caller.digitalprank.com/public_html/api_docs.md code Markdown # AI Prank Caller API Documentation (v1) Welcome to the AI Prank Caller API! This document provides all the information you need to integrate our prank calling functionality into your own applications. Access to the API is available to **Ultimate tier** subscribers. ## 1. Authentication Authentication is handled via an API key. You must include your key in the `X-API-KEY` header with every request. - **Header:** `X-API-KEY` - **Value:** `Your-Unique-API-Key` Requests without a valid API key will receive a `401 Unauthorized` or `403 Forbidden` response. --- ## 2. Endpoints ### 2.1. Send a Prank Call This is the primary endpoint for initiating a new prank call. The request is processed asynchronously. A successful response indicates that the call has been accepted for processing, not that it has been completed. - **URL:** `https://ai-prank-caller.digitalprank.com/api.php` - **Method:** `POST` - **Content-Type:** `application/json` #### Request Body | Parameter | Type | Required | Description | | ---------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------- | | `script_prompt` | String | Yes | The text you want the AI to speak. Must be between 10 and 500 characters. | | `victim_phone` | String | Yes | The recipient's phone number in E.164 format (e.g., `+15551234567`). | | `voice_style` | String | No | The voice to use. Defaults to `annoying_robot`. See below for available voices. | | `caller_id` | String | No | The number to display as the Caller ID, in E.164 format. If omitted, a default platform number is used. | #### Available `voice_style` Values - `annoying_robot` - `squeaky_chipmunk` - `scary_deep` - `sassy_female` - `movie_narrator` - `angry_neighbor` - `confused_old_lady` - `slick_salesman` - `nervous_guy` #### Example Request ```bash curl -X POST \ https://ai-prank-caller.digitalprank.com/api.php \ -H 'Content-Type: application/json' \ -H 'X-API-KEY: YOUR_API_KEY_HERE' \ -d '{ "script_prompt": "Hello? I am calling from the International Association of Lost Socks. We have located a missing argyle sock of yours. Please describe its partner for verification.", "victim_phone": "+15551234567", "voice_style": "movie_narrator", "caller_id": "+15558675309" }' Responses 202 Accepted (Success): The request was valid and the call has been queued. code JSON { "success": true, "message": "Prank call accepted.", "call_sid": "CAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "status": "queued" } 400 Bad Request: The request body is not valid JSON. 401/403 Unauthorized/Forbidden: The API key is missing or invalid. 422 Unprocessable Entity: The JSON is valid, but the data fails validation (e.g., missing required fields, invalid phone number format). code JSON { "success": false, "errors": [ "victim_phone is required and must be in E.164 format." ] } 429 Too Many Requests: You have exceeded your allowed API request rate. 500 Internal Server Error: A problem occurred on our end. 3. Rate Limiting The API is rate-limited to prevent abuse. The current limit is 10 requests per minute. If you exceed this limit, you will receive a 429 Too Many Requests response. Please design your application to handle this gracefully, for example, by using an exponential backoff strategy. code Code Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 31: /home/ai-prank-caller.digitalprank.com/public_html/database/prank_scripts_library.json code JSON { "categories": [ { "name": "Service Calls", "description": "Confusing calls from fictional services.", "scripts": [ { "title": "The Refrigerator Runner", "prompt": "Hello, this is Kevin from 'Running Refrigerators'. Is your refrigerator running? ... Well, you'd better go catch it! We'll be sending our team to help you track it down in the neighborhood shortly.", "suggested_voice": "slick_salesman" }, { "title": "Pigeon Rental Service", "prompt": "Hi, I'm calling to confirm your order for the deluxe pigeon rental package for this Friday. Our homing pigeons are very excited. Just a reminder, please do not feed them glitter. It was a problem last time.", "suggested_voice": "nervous_guy" }, { "title": "Emotional Support Ostrich", "prompt": "Good afternoon, this is a courtesy call from Animal Companions Inc. regarding your application for an emotional support ostrich. We need to schedule a home inspection to ensure your ceilings are high enough. He's a bit clumsy.", "suggested_voice": "sassy_female" } ] }, { "name": "Mistaken Identity", "description": "Pretending to be someone they're definitely not.", "scripts": [ { "title": "Space Mission Control", "prompt": "This is Star Command to Captain Lightyear. Do you copy? We've lost your signal since you entered the K-pax nebula. We need a status report on the alien squirrels. Over.", "suggested_voice": "movie_narrator" }, { "title": "Your Future Self", "prompt": "Listen carefully, it's you, from the future. Do NOT, I repeat, do NOT eat the spicy burrito for lunch tomorrow. It's a trap. Also, buy more toilet paper. You'll thank me later.", "suggested_voice": "scary_deep" }, { "title": "Spy Handler", "prompt": "Agent 7, the package has been delivered. The eagle has landed. I repeat, the eagle has landed. Your next mission, should you choose to accept it, is to retrieve the milk from the corner store. This message will self-destruct.", "suggested_voice": "annoying_robot" } ] }, { "name": "Custom Complaints", "description": "Hilarious complaints about non-existent problems.", "scripts": [ { "title": "Lawn Gnomes Union", "prompt": "Yes, hello. I represent the Local 42 Garden Gnomes Union. It has come to our attention that the gnome in your front yard is being forced to work overtime without adequate sun protection. This is a violation of our collective bargaining agreement.", "suggested_voice": "angry_neighbor" }, { "title": "Cat Interpreter", "prompt": "Hi, I'm a professional cat interpreter, and I'm here with your cat, Mittens. She's asked me to call you and express her deep disappointment with the quality of the sunbeams in the living room this morning. She expects better.", "suggested_voice": "sassy_female" }, { "title": "Confused Grandma", "prompt": "Hello dearie, is that you? I tried to send you a picture on The Google, but it ended up in my toaster. The bread came out with your face on it! Can you come over and fix the internet machine?", "suggested_voice": "confused_old_lady" } ] } ] } FILE 32: /home/ai-prank-caller.digitalprank.com/public_html/ajax_get_scripts.php code PHP false, 'message' => 'Script library is currently unavailable.']); exit; } try { $content = file_get_contents($library_file); $library_data = json_decode($content, true); if (json_last_error() !== JSON_ERROR_NONE) { throw new Exception('Error parsing script library data.'); } echo json_encode(['success' => true, 'data' => $library_data]); } catch (Exception $e) { http_response_code(500); error_log("Script Library Error: " . $e->getMessage()); echo json_encode(['success' => false, 'message' => 'Could not retrieve script library.']); } FILE 33: /home/ai-prank-caller.digitalprank.com/public_html/tool_form.php code PHP
    Describe a scenario or type the full message.
    >
    FILE 34: /home/ai-prank-caller.digitalprank.com/public_html/assets/js/main.js code JavaScript /** * Main JavaScript file (VERSION 1.2 - WITH SCRIPT LIBRARY) */ document.addEventListener('DOMContentLoaded', function() { // ... (Existing variables for form, modals, etc.) const openScriptLibraryButton = document.getElementById('openScriptLibrary'); const scriptLibraryModal = document.getElementById('scriptLibraryModal'); const closeScriptLibraryModal = document.getElementById('closeScriptLibraryModal'); const scriptLibraryContent = document.getElementById('scriptLibraryContent'); const scriptPromptTextarea = document.getElementById('script_prompt'); const voiceStyleSelect = document.getElementById('voice_style'); /** * Fetches scripts from the server and populates the library modal. */ async function loadScriptLibrary() { try { const response = await fetch('ajax_get_scripts.php'); if (!response.ok) { throw new Error('Network response was not ok.'); } const result = await response.json(); if (result.success && result.data.categories) { scriptLibraryContent.innerHTML = ''; // Clear spinner result.data.categories.forEach(category => { const categoryDiv = document.createElement('div'); categoryDiv.className = 'category'; const categoryTitle = document.createElement('h4'); categoryTitle.textContent = category.name; categoryDiv.appendChild(categoryTitle); category.scripts.forEach(script => { const scriptItem = document.createElement('div'); scriptItem.className = 'script-item'; scriptItem.innerHTML = `${script.title}${script.prompt}`; // Add event listener to populate the form when a script is clicked scriptItem.addEventListener('click', () => { if (scriptPromptTextarea) { scriptPromptTextarea.value = script.prompt; } if (voiceStyleSelect && script.suggested_voice) { voiceStyleSelect.value = script.suggested_voice; } hideScriptLibraryModal(); }); categoryDiv.appendChild(scriptItem); }); scriptLibraryContent.appendChild(categoryDiv); }); } else { scriptLibraryContent.innerHTML = `

    ${result.message || 'Could not load scripts.'}

    `; } } catch (error) { console.error('Failed to load script library:', error); scriptLibraryContent.innerHTML = '

    An error occurred while trying to fetch the script library.

    '; } } function showScriptLibraryModal() { if (scriptLibraryModal) { scriptLibraryModal.style.display = 'flex'; // Load content only if it hasn't been loaded yet if (!scriptLibraryContent.hasChildNodes() || scriptLibraryContent.querySelector('.spinner')) { loadScriptLibrary(); } } } function hideScriptLibraryModal() { if (scriptLibraryModal) scriptLibraryModal.style.display = 'none'; } // --- Event Listeners --- // ... (Existing listeners for form submission, main modal, etc.) if (openScriptLibraryButton) { openScriptLibraryButton.addEventListener('click', showScriptLibraryModal); } if (closeScriptLibraryModal) { closeScriptLibraryModal.addEventListener('click', hideScriptLibraryModal); } // Add listener to close modal on outside click if (scriptLibraryModal) { scriptLibraryModal.addEventListener('click', (event) => { if (event.target === scriptLibraryModal) { hideScriptLibraryModal(); } }); } // ... (Rest of the script from the previous version) }); FILE 35: /home/cdn.digitalprank.com/public_html/php/user_functions.php code PHP 'free', 'level' => 0, // 0=Free, 1=Basic, 2=Gold, 3=Ultimate 'usage' => ['used' => 0, 'limit' => 10], // Default free limit 'has_pro_access' => false ]; if ($user_id === 0 || $pdo === null) { return $default_access; } try { // Find the user's highest active subscription plan $stmt = $pdo->prepare( "SELECT subscription_plan_id FROM wp_pms_member_subscriptions WHERE user_id = ? AND status = 'active' ORDER BY subscription_plan_id DESC LIMIT 1" ); $stmt->execute([$user_id]); $plan_id = $stmt->fetchColumn(); if ($plan_id) { switch ($plan_id) { case 176: case 186: // Ultimate Tier $default_access['tier'] = 'ultimate'; $default_access['level'] = 3; $default_access['has_pro_access'] = true; break; case 175: case 185: // Gold Tier $default_access['tier'] = 'gold'; $default_access['level'] = 2; $default_access['has_pro_access'] = true; break; case 174: case 184: // Basic Tier $default_access['tier'] = 'basic'; $default_access['level'] = 1; $default_access['has_pro_access'] = true; break; } } // Check for specific tool entitlements (e.g., one-off purchases) // This could override or grant access even without a subscription. // (Logic for wp_digitalprank_entitlements would go here) } catch (PDOException $e) { // If the database check fails, log the error and return default access. error_log("Failed to get user access level for user {$user_id}: " . $e->getMessage()); } return $default_access; } } // Add other core user functions like checkDailyUsage, logUsage etc. here... FILE 36: /home/ai-prank-caller.digitalprank.com/public_html/Dockerfile```dockerfile Dockerfile for AI Prank Caller Tool This provides a reproducible environment for development and deployment. --- Stage 1: PHP Base with Extensions --- FROM php:8.1-fpm as php_base Set working directory WORKDIR /var/www Install system dependencies required for PHP extensions and the tool RUN apt-get update && apt-get install -y libzip-dev unzip libpng-dev libjpeg62-turbo-dev libfreetype6-dev libonig-dev ffmpeg sox # Cleanup && apt-get clean && rm -rf /var/lib/apt/lists/* Install required PHP extensions RUN docker-php-ext-configure gd --with-freetype --with-jpeg && docker-php-ext-install -j$(nproc) gd && docker-php-ext-install pdo pdo_mysql mbstring zip exif pcntl bcmath Install Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer --- Stage 2: Application Build --- FROM php_base as app_build WORKDIR /var/www Copy composer files and install dependencies COPY composer.json composer.lock ./ RUN composer install --no-dev --no-scripts --no-autoloader --optimize-autoloader Copy application files COPY . . Run composer dump-autoload after copying files RUN composer dump-autoload --optimize --- Stage 3: Python Dependencies --- Using a slim Python image for the venv FROM python:3.9-slim as python_builder Install system deps for torch RUN apt-get update && apt-get install -y build-essential WORKDIR /opt/venv ENV VIRTUAL_ENV=/opt/venv ENV PATH="/opt/venv/bin:$PATH" Create and activate virtual environment RUN python -m venv . Install Python packages We install torch for CPU first to keep the image smaller. For GPU, use a different base image. RUN pip install --no-cache-dir torch torchaudio --index-url https://download.pytorch.org/whl/cpu && pip install --no-cache-dir 'xtts-cli' pydub twilio --- Final Stage: Production Image --- FROM php:8.1-fpm WORKDIR /var/www Copy PHP files and vendor directory from the build stage COPY --from=app_build /var/www /var/www Copy the entire Python virtual environment from the python builder stage COPY --from=python_builder /opt/venv /var/www/venv Set permissions RUN chown -R www-data:www-data /var/www/uploads && chown -R www-data:www-data /var/www/vendor && chown -R www-data:www-data /var/www/venv Expose port 9000 for PHP-FPM EXPOSE 9000 The default command is to start PHP-FPM, which is inherited from the base image CMD ["php-fpm"] code Code Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 37: /home/ai-prank-caller.digitalprank.com/public_html/phpunit.xml.dist code Xml tests/Unit tests/Integration lib services vendor FILE 38: /home/ai-prank-caller.digitalprank.com/public_html/tests/bootstrap.php code PHP pdoMock = $this->createMock(PDO::class); $this->stmtMock = $this->createMock(PDOStatement::class); // Sample configuration for the RateLimiter $this->config = [ 'identity' => ['slug' => 'ai-prank-caller'], 'limits' => [ 'rate_limit_per_minute' => 10, 'max_concurrent_requests' => 3 ] ]; // The prepare method on our PDO mock should always return our statement mock $this->pdoMock->method('prepare')->willReturn($this->stmtMock); } public function testIsAllowedWhenRequestCountIsBelowLimit(): void { // Arrange: Configure the mocked statement $this->stmtMock->expects($this->once()) ->method('execute') ->with(['127.0.0.1', 0, 'ai-prank-caller']); // Note: user_id is cast to int $this->stmtMock->expects($this->once()) ->method('fetchColumn') ->willReturn(5); // 5 requests, which is less than the limit of 10 $rateLimiter = new RateLimiter($this->pdoMock, $this->config); // Act: Call the method we are testing $isAllowed = $rateLimiter->isAllowed('127.0.0.1'); // Assert: The result should be true $this->assertTrue($isAllowed); } public function testIsDeniedWhenRequestCountIsAtLimit(): void { // Arrange $this->stmtMock->expects($this->once()) ->method('execute'); $this->stmtMock->expects($this->once()) ->method('fetchColumn') ->willReturn(10); // 10 requests, which is equal to the limit $rateLimiter = new RateLimiter($this->pdoMock, $this->config); // Act $isAllowed = $rateLimiter->isAllowed('123'); // Using user ID // Assert $this->assertFalse($isAllowed); } public function testIsDeniedWhenRequestCountIsOverLimit(): void { // Arrange $this->stmtMock->method('fetchColumn')->willReturn(11); $rateLimiter = new RateLimiter($this->pdoMock, $this->config); // Act $isAllowed = $rateLimiter->isAllowed('127.0.0.1'); // Assert $this->assertFalse($isAllowed); } } FILE 40: /home/ai-prank-caller.digitalprank.com/public_html/services/LoggerService.php code PHP logger = new Logger('DigitalPrankApp'); // Define the log file path. Ensure this directory is writable by the web server. $logFile = '/var/log/digitalprank/app.log'; try { // Log messages of level WARNING and above to the file $this->logger->pushHandler(new StreamHandler($logFile, Logger::WARNING)); } catch (\Exception $e) { // Fallback if the primary log directory is not writable $this->logger->pushHandler(new StreamHandler(sys_get_temp_dir() . '/app_error.log', Logger::WARNING)); $this->error('Primary log file is not writable.', ['path' => $logFile, 'error' => $e->getMessage()]); } } /** * Gets the single instance of the LoggerService. */ public static function getInstance(): LoggerService { if (self::$instance === null) { self::$instance = new LoggerService(); } return self::$instance; } // --- PSR-3 LoggerInterface Methods --- public function emergency(\Stringable|string $message, array $context = []): void { $this->logger->emergency($message, $context); } public function alert(\Stringable|string $message, array $context = []): void { $this->logger->alert($message, $context); } public function critical(\Stringable|string $message, array $context = []): void { $this->logger->critical($message, $context); } public function error(\Stringable|string $message, array $context = []): void { $this->logger->error($message, $context); } public function warning(\Stringable|string $message, array $context = []): void { $this->logger->warning($message, $context); } public function notice(\Stringable|string $message, array $context = []): void { $this->logger->notice($message, $context); } public function info(\Stringable|string $message, array $context = []): void { $this->logger->info($message, $context); } public function debug(\Stringable|string $message, array $context = []): void { $this->logger->debug($message, $context); } public function log($level, \Stringable|string $message, array $context = []): void { $this->logger->log($level, $message, $context); } } FILE 41: /home/ai-prank-caller.digitalprank.com/public_html/.github/workflows/deploy.yml code Yaml # GitHub Actions Workflow for Continuous Integration & Deployment name: CI & Deploy # Triggers the workflow on push events to the main branch on: push: branches: [ "main" ] pull_request: branches: [ "main" ] jobs: test-and-deploy: name: Test and Deploy runs-on: ubuntu-latest steps: # 1. Checkout the repository code - name: Checkout repository uses: actions/checkout@v3 # 2. Setup PHP environment - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.1' extensions: mbstring, pdo, pdo_mysql # Add extensions needed by the app tools: composer:v2 coverage: xdebug # Needed for code coverage reports # 3. Install Composer dependencies - name: Install Composer dependencies run: composer install --prefer-dist --no-progress # 4. Run PHPUnit tests - name: Run PHPUnit tests run: vendor/bin/phpunit --configuration phpunit.xml.dist # 5. Deploy to production (only on push to main) # This step uses rsync over SSH. You must configure secrets in your GitHub repository settings. # Secrets needed: # - SSH_HOST: The hostname or IP of your server. # - SSH_USER: The user to log in as. # - SSH_PRIVATE_KEY: The private SSH key for authentication. - name: Deploy to Production if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: appleboy/ssh-action@master with: host: ${{ secrets.SSH_HOST }} username: ${{ secrets.SSH_USER }} key: ${{ secrets.SSH_PRIVATE_KEY }} script: | echo "Starting deployment..." cd /home/ai-prank-caller.digitalprank.com/public_html # Put the site in maintenance mode (optional) # touch maintenance.flag # Pull the latest changes from the main branch git pull origin main # Install/update composer dependencies composer install --no-dev --optimize-autoloader # Clear any caches (if applicable) # php clear_cache.php # Set correct file permissions chown -R www-data:www-data . find . -type d -exec chmod 755 {} \; find . -type f -exec chmod 644 {} \; # Take the site out of maintenance mode # rm maintenance.flag echo "Deployment finished successfully!" FILE 42: /home/ai-prank-caller.digitalprank.com/public_html/locales/en_US.json code JSON { "tool_name": "AI Prank Call Bot", "tool_tagline": "Unleash hilarious, AI-powered prank calls on your friends!", "script_prompt_label": "Enter your prank script or idea", "script_prompt_placeholder": "e.g., A pizza guy who got lost in your closet.", "script_library_button": "Choose from Library", "voice_style_label": "Voice Style", "victim_phone_label": "Victim's Phone Number", "victim_phone_placeholder": "+15551234567", "caller_id_label": "Caller ID to Display (Optional)", "schedule_time_label": "Schedule Call Time", "use_ai_voice_label": "Use AI-Generated Voice", "submit_button": "Send Prank Call", "pro_badge": "PRO", "success_modal_title": "Success!", "error_modal_title": "Error", "success_message_default": "Your prank call has been queued successfully.", "error_rate_limit": "You are making requests too quickly. Please wait a moment." } FILE 43: /home/ai-prank-caller.digitalprank.com/public_html/lib/Translator.php code PHP translations = json_decode($jsonContent, true) ?? []; } else { // Log this error in a real application // LoggerService::getInstance()->warning("Language file not found.", ['locale' => $locale]); } } /** * Gets the single instance of the Translator. * @param string $locale The desired locale (e.g., 'en_US', 'es_ES'). */ public static function getInstance(string $locale = 'en_US'): Translator { // A more advanced implementation would handle multiple instances for different locales if (self::$instance === null) { self::$instance = new Translator($locale); } return self::$instance; } /** * Retrieves a translated string by its key. * If the key is not found, it returns the key itself. * * @param string $key The key of the string to translate. * @return string The translated string or the key as a fallback. */ public function get(string $key): string { return $this->translations[$key] ?? $key; } /** * Magic method to allow calling the translator like a function. * Example: $t = Translator::getInstance(); echo $t('tool_name'); * * @param string $key * @return string */ public function __invoke(string $key): string { return $this->get($key); } } /** * Global helper function for easy access to translations. * * @param string $key * @return string */ function __(string $key): string { return Translator::getInstance()->get($key); } Model ThinkingThoughts (experimental) Auto Expand to view model thoughts chevron_right FILE 44: /home/ai-prank-caller.digitalprank.com/public_html/lib/Security.php code PHP [$self], // Default for all fetch directives 'script-src' => [$self, "'unsafe-inline'"], // Allow our own scripts and inline event handlers/scripts 'style-src' => [$self, "'unsafe-inline'"], // Allow our own styles and inline styles 'img-src' => [$self, 'data:'], // Allow images from our domain and data URIs 'font-src' => [$self], 'connect-src' => [$self], // Restricts AJAX endpoints to our own domain 'frame-ancestors' => ["'none'"], // Disallow embedding in iframes 'form-action' => [$self], // Form submissions only to our domain 'base-uri' => [$self], 'object-src' => ["'none'"], // Disallow plugins like Flash ]; $policyParts = []; foreach ($directives as $directive => $sources) { $policyParts[] = $directive . ' ' . implode(' ', $sources); } $policy = implode('; ', $policyParts); header("Content-Security-Policy: " . $policy); } } FILE 45: /home/ai-prank-caller.digitalprank.com/public_html/assets/js/examples.js code JavaScript /** * Examples Handler for AI Prank Caller Tool * * Populates the form with predefined examples to help users get started. */ document.addEventListener('DOMContentLoaded', () => { const examplesContainer = document.querySelector('.examples-container'); const scriptPromptTextarea = document.getElementById('script_prompt'); const voiceStyleSelect = document.getElementById('voice_style'); if (!examplesContainer || !scriptPromptTextarea || !voiceStyleSelect) { return; // Exit if essential elements are not on the page } // The examples data is injected into a script tag in the HTML by PHP. // This avoids an extra AJAX request on page load. if (typeof toolExamples === 'undefined' || !Array.isArray(toolExamples)) { console.warn('Tool examples data is not available.'); return; } /** * Creates and appends example buttons to the container. */ function renderExampleButtons() { examplesContainer.innerHTML = ''; // Clear any existing content const title = document.createElement('h4'); title.textContent = 'Or, Try an Example:'; examplesContainer.appendChild(title); toolExamples.forEach((example, index) => { const button = document.createElement('button'); button.type = 'button'; button.className = 'example-button'; button.textContent = example.title; button.dataset.index = index; examplesContainer.appendChild(button); }); } /** * Handles clicks on the example buttons container. * @param {Event} event The click event. */ function handleExampleClick(event) { if (event.target.classList.contains('example-button')) { const index = event.target.dataset.index; const example = toolExamples[index]; if (example && example.input) { // Populate the form fields with the example data scriptPromptTextarea.value = example.input.script_prompt || ''; voiceStyleSelect.value = example.input.voice_style || voiceStyleSelect.options[0].value; // Optional: Scroll to the top of the form const toolForm = document.getElementById('toolForm'); if (toolForm) { toolForm.scrollIntoView({ behavior: 'smooth' }); } // Trigger an input event to let any other listeners know the value has changed scriptPromptTextarea.dispatchEvent(new Event('input', { bubbles: true })); } } } // --- Initialize --- renderExampleButtons(); examplesContainer.addEventListener('click', handleExampleClick); }); FILE 46: /home/ai-prank-caller.digitalprank.com/public_html/setup/register_tool.php code PHP setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { die("FATAL: Database connection failed: " . $e->getMessage() . "\n"); } echo "Database connection successful.\n"; // --- Prepare Data for Insertion --- $tool_data = [ 'slug' => $config['identity']['slug'], 'name' => $config['identity']['name'], 'subdomain' => explode('.', $config['identity']['slug'])[0], // ai-prank-caller 'category' => $config['identity']['category'], 'tagline' => $config['identity']['tagline'], 'description' => $config['identity']['description'], 'features_json' => json_encode($config['features']), 'free_monthly_limit' => $config['limits']['tier_daily']['free'] * 30, // Approximate monthly 'basic_monthly_limit' => $config['limits']['tier_daily']['basic'] * 30, 'gold_monthly_limit' => $config['limits']['tier_daily']['gold'] * 30, 'ultimate_monthly_limit' => $config['limits']['tier_daily']['ultimate'], 'is_active' => 1 ]; // --- SQL Statement (INSERT ... ON DUPLICATE KEY UPDATE) --- $sql = " INSERT INTO wp_digitalprank_tools ( slug, name, subdomain, category, tagline, description, features_json, free_monthly_limit, basic_monthly_limit, gold_monthly_limit, ultimate_monthly_limit, is_active ) VALUES ( :slug, :name, :subdomain, :category, :tagline, :description, :features_json, :free_monthly_limit, :basic_monthly_limit, :gold_monthly_limit, :ultimate_monthly_limit, :is_active ) ON DUPLICATE KEY UPDATE name = VALUES(name), subdomain = VALUES(subdomain), category = VALUES(category), tagline = VALUES(tagline), description = VALUES(description), features_json = VALUES(features_json), free_monthly_limit = VALUES(free_monthly_limit), basic_monthly_limit = VALUES(basic_monthly_limit), gold_monthly_limit = VALUES(gold_monthly_limit), ultimate_monthly_limit = VALUES(ultimate_monthly_limit), is_active = VALUES(is_active), updated_at = NOW(); "; try { $stmt = $pdo->prepare($sql); $stmt->execute($tool_data); echo "SUCCESS: Tool '{$config['identity']['slug']}' has been successfully registered/updated in the platform database.\n"; } catch (PDOException $e) { die("FATAL: Failed to execute registration query: " . $e->getMessage() . "\n"); } echo "--- Registration Complete ---\n"; echo "RECOMMENDATION: Please delete this file ('" . __FILE__ . "') from the server now.\n"; FILE 47: /home/ai-prank-caller.digitalprank.com/public_html/robots.txt code Code # robots.txt for AI Prank Caller Tool # This file tells search engine crawlers which pages or files the crawler # can or can't request from your site. User-agent: * # Allow crawlers to access the main page and help documentation Allow: / Allow: /help.md # Disallow crawling of backend scripts and sensitive areas Disallow: /processor.php Disallow: /ajax_get_scripts.php Disallow: /api.php Disallow: /admin/ Disallow: /vendor/ Disallow: /services/ Disallow: /lib/ Disallow: /setup/ Disallow: /tests/ Disallow: /database/ Disallow: /*.json$ Disallow: /*.sql$ Disallow: /*.lock$ Disallow: /*.yml$ Disallow: /history.php Disallow: /twilio_status_webhook.php Disallow: /twilio_handler.php # Path to the sitemap (optional but recommended) # Sitemap: https://ai-prank-caller.digitalprank.com/sitemap.xml FILE 48: /home/ai-prank-caller.digitalprank.com/public_html/manifest.webmanifest code JSON { "name": "AI Prank Caller", "short_name": "Prank Call", "description": "Send funny, automated prank calls using AI voices.", "start_url": "/index.php", "display": "standalone", "background_color": "#1a1a1a", "theme_color": "#FF4500", "icons": [ { "src": "/assets/icons/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/assets/icons/icon-512x512.png", "sizes": "512x512", "type": "image/png" }, { "src": "/assets/icons/icon-maskable.png", "sizes": "192x192", "type": "image/png", "purpose": "maskable" } ] } FILE 49: /home/ai-prank-caller.digitalprank.com/public_html/index.php code PHP false]; // Mock for display // CSRF token if (empty($_SESSION['csrf_token'])) $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); $csrf_token = $_SESSION['csrf_token']; ?>
    FILE 50: /home/ai-prank-caller.digitalprank.com/public_html/bootstrap.php code PHP get(); } catch (Exception $e) { LoggerService::getInstance()->critical("Config load failed", ['error' => $e->getMessage()]); die("Fatal Error: Could not load tool configuration."); } // --- Database Connection --- $db_host = 'localhost'; $db_name = 'digitalprank_db'; $db_user = 'dp_user'; $db_pass = '#$Dealer2355'; $pdo = null; try { $pdo = new PDO("mysql:host=$db_host;dbname=$db_name;charset=utf8mb4", $db_user, $db_pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]); } catch (PDOException $e) { LoggerService::getInstance()->emergency("Database connection failed", ['error' => $e->getMessage()]); die("Fatal Error: Database service is unavailable."); } // --- Session Initialization --- session_start([ 'cookie_httponly' => true, 'cookie_secure' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on', 'cookie_samesite' => 'Lax' ]); // --- Service Initialization --- // Services are now initialized on-demand where needed, or here if truly global. // For instance, the Logger can be initialized here. $logger = LoggerService::getInstance();