911 lines
36 KiB
PHP
Executable File
911 lines
36 KiB
PHP
Executable File
|
|
<?php
|
|
/**
|
|
* MASTER MONITOR API
|
|
* - ALL AI Providers (Free + Paid) with dynamic update
|
|
* - Error detection (500, 404, regressions)
|
|
* - Cache cleaner
|
|
* - Zombie killer (PMTA servers)
|
|
* - Tracking system monitor
|
|
* - URL/Send validation matrix
|
|
*/
|
|
header('Content-Type: application/json');
|
|
error_reporting(E_ALL);
|
|
|
|
$db = new PDO("pgsql:host=127.0.0.1;dbname=adx_system", "admin", "admin123");
|
|
|
|
// ==================== COMPLETE AI PROVIDERS DATABASE ====================
|
|
$ALL_AI_PROVIDERS = [
|
|
// ============ FREE TIER ============
|
|
'groq' => [
|
|
'name' => 'Groq',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://api.groq.com/openai/v1/chat/completions',
|
|
'models' => ['llama-3.3-70b-versatile', 'llama-3.1-8b-instant', 'llama-3.2-90b-vision-preview', 'mixtral-8x7b-32768', 'gemma2-9b-it', 'whisper-large-v3'],
|
|
'capabilities' => ['text', 'code', 'vision', 'voice_transcription'],
|
|
'rate_limit' => '30 req/min, 14400/day',
|
|
'cost' => 'FREE',
|
|
'speed' => 'ultra_fast',
|
|
'quality' => 8,
|
|
'signup' => 'https://console.groq.com'
|
|
],
|
|
'cerebras' => [
|
|
'name' => 'Cerebras',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://api.cerebras.ai/v1/chat/completions',
|
|
'models' => ['llama3.1-8b', 'llama3.1-70b'],
|
|
'capabilities' => ['text', 'code'],
|
|
'rate_limit' => '30 req/min',
|
|
'cost' => 'FREE',
|
|
'speed' => 'ultra_fast',
|
|
'quality' => 7,
|
|
'signup' => 'https://cloud.cerebras.ai'
|
|
],
|
|
'sambanova' => [
|
|
'name' => 'SambaNova',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://api.sambanova.ai/v1/chat/completions',
|
|
'models' => ['Meta-Llama-3.1-8B-Instruct', 'Meta-Llama-3.1-70B-Instruct', 'Meta-Llama-3.1-405B-Instruct'],
|
|
'capabilities' => ['text', 'code'],
|
|
'rate_limit' => '10 req/min',
|
|
'cost' => 'FREE',
|
|
'speed' => 'fast',
|
|
'quality' => 8,
|
|
'signup' => 'https://cloud.sambanova.ai'
|
|
],
|
|
'hyperbolic' => [
|
|
'name' => 'Hyperbolic',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://api.hyperbolic.xyz/v1/chat/completions',
|
|
'models' => ['meta-llama/Llama-3.2-3B-Instruct', 'Qwen/Qwen2.5-72B-Instruct', 'deepseek-ai/DeepSeek-V2.5'],
|
|
'capabilities' => ['text', 'code', 'image_gen'],
|
|
'rate_limit' => 'Generous free tier',
|
|
'cost' => 'FREE',
|
|
'speed' => 'fast',
|
|
'quality' => 8,
|
|
'signup' => 'https://hyperbolic.xyz'
|
|
],
|
|
'glhf' => [
|
|
'name' => 'GLHF Chat',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://glhf.chat/api/openai/v1/chat/completions',
|
|
'models' => ['hf:meta-llama/Llama-3.1-405B-Instruct', 'hf:mistralai/Mistral-7B-Instruct-v0.3'],
|
|
'capabilities' => ['text', 'code'],
|
|
'rate_limit' => 'Free',
|
|
'cost' => 'FREE',
|
|
'speed' => 'medium',
|
|
'quality' => 9,
|
|
'signup' => 'https://glhf.chat'
|
|
],
|
|
'openrouter_free' => [
|
|
'name' => 'OpenRouter (Free)',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://openrouter.ai/api/v1/chat/completions',
|
|
'models' => ['meta-llama/llama-3.1-8b-instruct:free', 'google/gemma-2-9b-it:free', 'mistralai/mistral-7b-instruct:free', 'huggingfaceh4/zephyr-7b-beta:free'],
|
|
'capabilities' => ['text', 'aggregator'],
|
|
'rate_limit' => '20 req/min free models',
|
|
'cost' => 'FREE',
|
|
'speed' => 'medium',
|
|
'quality' => 7,
|
|
'signup' => 'https://openrouter.ai'
|
|
],
|
|
'gemini' => [
|
|
'name' => 'Google Gemini',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://generativelanguage.googleapis.com/v1beta/models',
|
|
'models' => ['gemini-1.5-flash', 'gemini-1.5-flash-8b', 'gemini-1.5-pro', 'gemini-2.0-flash-exp', 'gemini-exp-1206'],
|
|
'capabilities' => ['text', 'image', 'video', 'audio', 'code', 'function_calling'],
|
|
'rate_limit' => '60 req/min, 1500/day',
|
|
'cost' => 'FREE (generous)',
|
|
'speed' => 'fast',
|
|
'quality' => 9,
|
|
'signup' => 'https://aistudio.google.com'
|
|
],
|
|
'cloudflare_ai' => [
|
|
'name' => 'Cloudflare Workers AI',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/run',
|
|
'models' => ['@cf/meta/llama-3.1-8b-instruct', '@cf/mistral/mistral-7b-instruct-v0.1', '@cf/qwen/qwen1.5-14b-chat-awq'],
|
|
'capabilities' => ['text', 'image_gen', 'embeddings'],
|
|
'rate_limit' => '10000 neurons/day free',
|
|
'cost' => 'FREE',
|
|
'speed' => 'fast',
|
|
'quality' => 7,
|
|
'signup' => 'https://dash.cloudflare.com'
|
|
],
|
|
'huggingface_inference' => [
|
|
'name' => 'HuggingFace Inference',
|
|
'type' => 'free',
|
|
'endpoint' => 'https://api-inference.huggingface.co/models',
|
|
'models' => ['meta-llama/Llama-3.2-3B-Instruct', 'mistralai/Mistral-7B-Instruct-v0.3', 'google/gemma-2-2b-it'],
|
|
'capabilities' => ['text', 'image_gen', 'embeddings', 'audio'],
|
|
'rate_limit' => 'Rate limited free',
|
|
'cost' => 'FREE',
|
|
'speed' => 'slow',
|
|
'quality' => 7,
|
|
'signup' => 'https://huggingface.co'
|
|
],
|
|
|
|
// ============ FREE TRIAL / CREDITS ============
|
|
'mistral' => [
|
|
'name' => 'Mistral AI',
|
|
'type' => 'free_trial',
|
|
'endpoint' => 'https://api.mistral.ai/v1/chat/completions',
|
|
'models' => ['mistral-large-latest', 'mistral-small-latest', 'codestral-latest', 'pixtral-12b-2409', 'mistral-embed'],
|
|
'capabilities' => ['text', 'code', 'vision', 'embeddings'],
|
|
'rate_limit' => '€5 free credit',
|
|
'cost' => '€5 FREE then paid',
|
|
'speed' => 'fast',
|
|
'quality' => 9,
|
|
'signup' => 'https://console.mistral.ai'
|
|
],
|
|
'cohere' => [
|
|
'name' => 'Cohere',
|
|
'type' => 'free_trial',
|
|
'endpoint' => 'https://api.cohere.ai/v1/chat',
|
|
'models' => ['command-r-plus', 'command-r', 'command-light', 'embed-english-v3.0'],
|
|
'capabilities' => ['text', 'rag', 'embeddings', 'rerank'],
|
|
'rate_limit' => '1000 req/month free',
|
|
'cost' => 'FREE trial then paid',
|
|
'speed' => 'medium',
|
|
'quality' => 8,
|
|
'signup' => 'https://dashboard.cohere.com'
|
|
],
|
|
'together' => [
|
|
'name' => 'Together AI',
|
|
'type' => 'free_trial',
|
|
'endpoint' => 'https://api.together.xyz/v1/chat/completions',
|
|
'models' => ['meta-llama/Llama-3.2-90B-Vision-Instruct-Turbo', 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo', 'mistralai/Mixtral-8x22B-Instruct-v0.1', 'Qwen/Qwen2.5-72B-Instruct-Turbo'],
|
|
'capabilities' => ['text', 'code', 'vision', 'image_gen'],
|
|
'rate_limit' => '$25 free credit',
|
|
'cost' => '$25 FREE then paid',
|
|
'speed' => 'fast',
|
|
'quality' => 9,
|
|
'signup' => 'https://api.together.xyz'
|
|
],
|
|
'fireworks' => [
|
|
'name' => 'Fireworks AI',
|
|
'type' => 'free_trial',
|
|
'endpoint' => 'https://api.fireworks.ai/inference/v1/chat/completions',
|
|
'models' => ['accounts/fireworks/models/llama-v3p1-405b-instruct', 'accounts/fireworks/models/llama-v3p2-90b-vision-instruct', 'accounts/fireworks/models/mixtral-8x22b-instruct'],
|
|
'capabilities' => ['text', 'code', 'vision', 'function_calling'],
|
|
'rate_limit' => '$1 free credit',
|
|
'cost' => '$1 FREE then cheap',
|
|
'speed' => 'fast',
|
|
'quality' => 9,
|
|
'signup' => 'https://fireworks.ai'
|
|
],
|
|
'novita' => [
|
|
'name' => 'Novita AI',
|
|
'type' => 'free_trial',
|
|
'endpoint' => 'https://api.novita.ai/v3/openai/chat/completions',
|
|
'models' => ['meta-llama/llama-3.1-70b-instruct', 'meta-llama/llama-3.1-405b-instruct', 'mistralai/mistral-nemo'],
|
|
'capabilities' => ['text', 'image_gen', 'video_gen'],
|
|
'rate_limit' => '$0.5 free credit',
|
|
'cost' => '$0.5 FREE then paid',
|
|
'speed' => 'medium',
|
|
'quality' => 8,
|
|
'signup' => 'https://novita.ai'
|
|
],
|
|
'lepton' => [
|
|
'name' => 'Lepton AI',
|
|
'type' => 'free_trial',
|
|
'endpoint' => 'https://llama3-1-405b.lepton.run/api/v1/chat/completions',
|
|
'models' => ['llama3-1-405b', 'llama3-1-70b', 'mixtral-8x7b'],
|
|
'capabilities' => ['text', 'code'],
|
|
'rate_limit' => 'Free trial',
|
|
'cost' => 'FREE trial',
|
|
'speed' => 'fast',
|
|
'quality' => 9,
|
|
'signup' => 'https://www.lepton.ai'
|
|
],
|
|
'anyscale' => [
|
|
'name' => 'Anyscale',
|
|
'type' => 'free_trial',
|
|
'endpoint' => 'https://api.endpoints.anyscale.com/v1/chat/completions',
|
|
'models' => ['meta-llama/Llama-3-70b-chat-hf', 'mistralai/Mixtral-8x7B-Instruct-v0.1'],
|
|
'capabilities' => ['text', 'code'],
|
|
'rate_limit' => '$10 free credit',
|
|
'cost' => '$10 FREE then paid',
|
|
'speed' => 'fast',
|
|
'quality' => 8,
|
|
'signup' => 'https://www.anyscale.com'
|
|
],
|
|
'replicate' => [
|
|
'name' => 'Replicate',
|
|
'type' => 'free_trial',
|
|
'endpoint' => 'https://api.replicate.com/v1/predictions',
|
|
'models' => ['meta/llama-2-70b-chat', 'mistralai/mixtral-8x7b-instruct-v0.1', 'stability-ai/sdxl'],
|
|
'capabilities' => ['text', 'image_gen', 'video_gen', 'audio'],
|
|
'rate_limit' => 'Pay per use',
|
|
'cost' => 'Free trial then paid',
|
|
'speed' => 'slow',
|
|
'quality' => 8,
|
|
'signup' => 'https://replicate.com'
|
|
],
|
|
|
|
// ============ CHEAP / VALUE ============
|
|
'deepseek' => [
|
|
'name' => 'DeepSeek',
|
|
'type' => 'cheap',
|
|
'endpoint' => 'https://api.deepseek.com/chat/completions',
|
|
'models' => ['deepseek-chat', 'deepseek-coder', 'deepseek-reasoner'],
|
|
'capabilities' => ['text', 'code', 'reasoning', 'analysis'],
|
|
'rate_limit' => 'High limits',
|
|
'cost' => '$0.14/1M input, $0.28/1M output',
|
|
'speed' => 'fast',
|
|
'quality' => 9,
|
|
'signup' => 'https://platform.deepseek.com'
|
|
],
|
|
'openrouter' => [
|
|
'name' => 'OpenRouter (Paid)',
|
|
'type' => 'aggregator',
|
|
'endpoint' => 'https://openrouter.ai/api/v1/chat/completions',
|
|
'models' => ['anthropic/claude-3.5-sonnet', 'openai/gpt-4o', 'google/gemini-pro-1.5', 'meta-llama/llama-3.1-405b-instruct'],
|
|
'capabilities' => ['text', 'image', 'code', 'all_models'],
|
|
'rate_limit' => 'Per model',
|
|
'cost' => 'Variable (often cheaper)',
|
|
'speed' => 'medium',
|
|
'quality' => 10,
|
|
'signup' => 'https://openrouter.ai'
|
|
],
|
|
|
|
// ============ PREMIUM / PAID ============
|
|
'anthropic' => [
|
|
'name' => 'Anthropic Claude',
|
|
'type' => 'paid',
|
|
'endpoint' => 'https://api.anthropic.com/v1/messages',
|
|
'models' => ['claude-3-5-sonnet-20241022', 'claude-3-5-haiku-20241022', 'claude-3-opus-20240229'],
|
|
'capabilities' => ['text', 'image', 'code', 'analysis', 'reasoning', 'computer_use'],
|
|
'rate_limit' => '4000 req/min',
|
|
'cost' => '$3-15/1M tokens',
|
|
'speed' => 'medium',
|
|
'quality' => 10,
|
|
'signup' => 'https://console.anthropic.com'
|
|
],
|
|
'openai' => [
|
|
'name' => 'OpenAI',
|
|
'type' => 'paid',
|
|
'endpoint' => 'https://api.openai.com/v1/chat/completions',
|
|
'models' => ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'o1-preview', 'o1-mini', 'dall-e-3', 'whisper-1', 'tts-1'],
|
|
'capabilities' => ['text', 'image', 'vision', 'voice', 'tts', 'code', 'reasoning'],
|
|
'rate_limit' => 'Tier based',
|
|
'cost' => '$2.50-60/1M tokens',
|
|
'speed' => 'fast',
|
|
'quality' => 10,
|
|
'signup' => 'https://platform.openai.com'
|
|
],
|
|
'perplexity' => [
|
|
'name' => 'Perplexity',
|
|
'type' => 'paid',
|
|
'endpoint' => 'https://api.perplexity.ai/chat/completions',
|
|
'models' => ['llama-3.1-sonar-large-128k-online', 'llama-3.1-sonar-small-128k-online', 'llama-3.1-sonar-huge-128k-online'],
|
|
'capabilities' => ['text', 'search', 'rag', 'citations'],
|
|
'rate_limit' => 'Per subscription',
|
|
'cost' => '$0.20-5/1M tokens',
|
|
'speed' => 'medium',
|
|
'quality' => 9,
|
|
'signup' => 'https://www.perplexity.ai/settings/api'
|
|
],
|
|
'azure_openai' => [
|
|
'name' => 'Azure OpenAI',
|
|
'type' => 'paid',
|
|
'endpoint' => 'https://{resource}.openai.azure.com/openai/deployments/{deployment}/chat/completions',
|
|
'models' => ['gpt-4o', 'gpt-4-turbo', 'gpt-35-turbo'],
|
|
'capabilities' => ['text', 'image', 'voice', 'code'],
|
|
'rate_limit' => 'Quota based',
|
|
'cost' => 'Similar to OpenAI',
|
|
'speed' => 'fast',
|
|
'quality' => 10,
|
|
'signup' => 'https://azure.microsoft.com/en-us/products/ai-services/openai-service'
|
|
],
|
|
'aws_bedrock' => [
|
|
'name' => 'AWS Bedrock',
|
|
'type' => 'paid',
|
|
'endpoint' => 'https://bedrock-runtime.{region}.amazonaws.com',
|
|
'models' => ['anthropic.claude-3-5-sonnet', 'meta.llama3-1-405b-instruct', 'amazon.titan-text-premier'],
|
|
'capabilities' => ['text', 'image', 'code', 'embeddings'],
|
|
'rate_limit' => 'Quota based',
|
|
'cost' => 'Per model pricing',
|
|
'speed' => 'fast',
|
|
'quality' => 10,
|
|
'signup' => 'https://aws.amazon.com/bedrock/'
|
|
],
|
|
'vertex_ai' => [
|
|
'name' => 'Google Vertex AI',
|
|
'type' => 'paid',
|
|
'endpoint' => 'https://{region}-aiplatform.googleapis.com/v1/projects/{project}/locations/{region}/publishers/google/models',
|
|
'models' => ['gemini-1.5-pro', 'gemini-1.5-flash', 'text-bison', 'code-bison'],
|
|
'capabilities' => ['text', 'image', 'video', 'code', 'embeddings'],
|
|
'rate_limit' => 'Quota based',
|
|
'cost' => 'Per model pricing',
|
|
'speed' => 'fast',
|
|
'quality' => 9,
|
|
'signup' => 'https://console.cloud.google.com/vertex-ai'
|
|
],
|
|
|
|
// ============ SPECIALIZED ============
|
|
'eleven_labs' => [
|
|
'name' => 'ElevenLabs',
|
|
'type' => 'specialized',
|
|
'endpoint' => 'https://api.elevenlabs.io/v1',
|
|
'models' => ['eleven_multilingual_v2', 'eleven_turbo_v2'],
|
|
'capabilities' => ['tts', 'voice_clone', 'audio'],
|
|
'rate_limit' => '10000 chars/month free',
|
|
'cost' => 'FREE tier then paid',
|
|
'speed' => 'fast',
|
|
'quality' => 10,
|
|
'signup' => 'https://elevenlabs.io'
|
|
],
|
|
'stability' => [
|
|
'name' => 'Stability AI',
|
|
'type' => 'specialized',
|
|
'endpoint' => 'https://api.stability.ai/v1/generation',
|
|
'models' => ['stable-diffusion-xl-1024-v1-0', 'stable-image-ultra', 'stable-video-diffusion'],
|
|
'capabilities' => ['image_gen', 'video_gen', 'image_edit'],
|
|
'rate_limit' => '25 credits free',
|
|
'cost' => 'Credits based',
|
|
'speed' => 'medium',
|
|
'quality' => 10,
|
|
'signup' => 'https://platform.stability.ai'
|
|
],
|
|
'assemblyai' => [
|
|
'name' => 'AssemblyAI',
|
|
'type' => 'specialized',
|
|
'endpoint' => 'https://api.assemblyai.com/v2',
|
|
'models' => ['best', 'nano'],
|
|
'capabilities' => ['transcription', 'speaker_diarization', 'sentiment'],
|
|
'rate_limit' => '5 hours free',
|
|
'cost' => '$0.37/hour',
|
|
'speed' => 'medium',
|
|
'quality' => 10,
|
|
'signup' => 'https://www.assemblyai.com'
|
|
]
|
|
];
|
|
|
|
$action = $_POST['action'] ?? $_GET['action'] ?? '';
|
|
$response = ['success' => false];
|
|
|
|
switch ($action) {
|
|
|
|
// ==================== LIST ALL PROVIDERS ====================
|
|
case 'list_all_providers':
|
|
$byType = [
|
|
'free' => [],
|
|
'free_trial' => [],
|
|
'cheap' => [],
|
|
'paid' => [],
|
|
'specialized' => [],
|
|
'aggregator' => []
|
|
];
|
|
|
|
foreach ($ALL_AI_PROVIDERS as $key => $p) {
|
|
$byType[$p['type']][] = array_merge(['key' => $key], $p);
|
|
}
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'providers' => $ALL_AI_PROVIDERS,
|
|
'by_type' => $byType,
|
|
'total' => count($ALL_AI_PROVIDERS),
|
|
'free_count' => count($byType['free']) + count($byType['free_trial'])
|
|
];
|
|
break;
|
|
|
|
// ==================== SYNC PROVIDERS TO DB ====================
|
|
case 'sync_providers':
|
|
$synced = 0;
|
|
foreach ($ALL_AI_PROVIDERS as $key => $p) {
|
|
$stmt = $db->prepare("INSERT INTO admin.ai_providers
|
|
(name, provider_key, endpoint, model, capabilities, rate_limit, cost, speed_rating, quality_rating, provider_type, signup_url)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT (provider_key) DO UPDATE SET
|
|
name = EXCLUDED.name,
|
|
endpoint = EXCLUDED.endpoint,
|
|
model = EXCLUDED.model,
|
|
capabilities = EXCLUDED.capabilities,
|
|
rate_limit = EXCLUDED.rate_limit,
|
|
cost = EXCLUDED.cost");
|
|
|
|
$stmt->execute([
|
|
$p['name'],
|
|
$key,
|
|
$p['endpoint'],
|
|
$p['models'][0],
|
|
json_encode($p['capabilities']),
|
|
$p['rate_limit'],
|
|
$p['cost'],
|
|
$p['speed'] == 'ultra_fast' ? 10 : ($p['speed'] == 'fast' ? 8 : 5),
|
|
$p['quality'],
|
|
$p['type'],
|
|
$p['signup']
|
|
]);
|
|
$synced++;
|
|
}
|
|
|
|
$response = ['success' => true, 'synced' => $synced];
|
|
break;
|
|
|
|
// ==================== ERROR DETECTION & AUTO-REPAIR ====================
|
|
case 'check_errors':
|
|
$errors = [];
|
|
|
|
// Check Apache error log for 500s
|
|
$apacheErrors = shell_exec("grep -c '500' /var/log/apache2/error.log 2>/dev/null || echo 0");
|
|
$errors['apache_500'] = intval(trim($apacheErrors));
|
|
|
|
// Check for 404s in access log
|
|
$notFound = shell_exec("grep -c ' 404 ' /var/log/apache2/access.log 2>/dev/null | tail -1000 || echo 0");
|
|
$errors['apache_404'] = intval(trim($notFound));
|
|
|
|
// Check PHP fatal errors
|
|
$phpFatal = shell_exec("grep -c 'Fatal error' /var/log/apache2/error.log 2>/dev/null || echo 0");
|
|
$errors['php_fatal'] = intval(trim($phpFatal));
|
|
|
|
// Check specific WEVAL endpoints
|
|
$endpoints = [
|
|
'wevads_main' => 'http://127.0.0.1:5821/',
|
|
'hamid_api' => 'http://127.0.0.1:5821/hamid-api.php?action=health',
|
|
'send_control' => 'http://127.0.0.1:5821/deliverads/send-control.php',
|
|
'ceo_pilotage' => 'http://127.0.0.1:5821/ceo-pilotage.php',
|
|
'tracking_58421' => 'http://127.0.0.1:58421/',
|
|
'n8n' => 'http://127.0.0.1:5678/'
|
|
];
|
|
|
|
$endpointStatus = [];
|
|
foreach ($endpoints as $name => $url) {
|
|
$ch = curl_init($url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
|
|
curl_setopt($ch, CURLOPT_NOBODY, true);
|
|
curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
$endpointStatus[$name] = [
|
|
'url' => $url,
|
|
'status' => $httpCode,
|
|
'ok' => ($httpCode >= 200 && $httpCode < 400)
|
|
];
|
|
|
|
if ($httpCode >= 500) {
|
|
$errors['endpoint_' . $name] = $httpCode;
|
|
}
|
|
}
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'errors' => $errors,
|
|
'endpoints' => $endpointStatus,
|
|
'total_errors' => array_sum($errors),
|
|
'critical' => array_sum($errors) > 10
|
|
];
|
|
break;
|
|
|
|
// ==================== AUTO-REPAIR ERRORS ====================
|
|
case 'auto_repair':
|
|
$repairs = [];
|
|
|
|
// 1. Clear OPcache
|
|
if (function_exists('opcache_reset')) {
|
|
opcache_reset();
|
|
$repairs[] = 'OPcache cleared';
|
|
}
|
|
|
|
// 2. Restart PHP-FPM if many errors
|
|
$phpErrors = shell_exec("grep -c 'Fatal error' /var/log/apache2/error.log 2>/dev/null || echo 0");
|
|
if (intval(trim($phpErrors)) > 10) {
|
|
shell_exec('systemctl restart php7.4-fpm 2>&1');
|
|
$repairs[] = 'PHP-FPM restarted';
|
|
}
|
|
|
|
// 3. Check and restart Apache if needed
|
|
$apacheStatus = trim(shell_exec('systemctl is-active apache2'));
|
|
if ($apacheStatus !== 'active') {
|
|
shell_exec('systemctl restart apache2 2>&1');
|
|
$repairs[] = 'Apache restarted';
|
|
}
|
|
|
|
// 4. Clear APC cache
|
|
if (function_exists('apc_clear_cache')) {
|
|
apc_clear_cache();
|
|
apc_clear_cache('user');
|
|
$repairs[] = 'APC cache cleared';
|
|
}
|
|
|
|
// 5. Clear Redis cache if saturated
|
|
$redisInfo = shell_exec('redis-cli info memory 2>/dev/null | grep used_memory_human');
|
|
if (strpos($redisInfo, 'G') !== false) { // If using GB
|
|
shell_exec('redis-cli FLUSHDB 2>&1');
|
|
$repairs[] = 'Redis cache cleared';
|
|
}
|
|
|
|
// 6. Log repair
|
|
$db->prepare("INSERT INTO admin.orchestrator_log (source, action, data, status) VALUES ('auto-repair', 'repair_executed', ?, 'success')")
|
|
->execute([json_encode($repairs)]);
|
|
|
|
$response = ['success' => true, 'repairs' => $repairs];
|
|
break;
|
|
|
|
// ==================== CLEAR ALL CACHES ====================
|
|
case 'clear_all_caches':
|
|
$cleared = [];
|
|
|
|
// OPcache
|
|
if (function_exists('opcache_reset')) {
|
|
opcache_reset();
|
|
$cleared[] = 'OPcache';
|
|
}
|
|
|
|
// Redis
|
|
shell_exec('redis-cli FLUSHALL 2>&1');
|
|
$cleared[] = 'Redis';
|
|
|
|
// APCu
|
|
if (function_exists('apcu_clear_cache')) {
|
|
apcu_clear_cache();
|
|
$cleared[] = 'APCu';
|
|
}
|
|
|
|
// PHP session files (old ones)
|
|
shell_exec('find /var/lib/php/sessions -type f -mtime +1 -delete 2>&1');
|
|
$cleared[] = 'Old PHP sessions';
|
|
|
|
// Temp files
|
|
shell_exec('rm -rf /tmp/wevads_* 2>&1');
|
|
$cleared[] = 'Temp files';
|
|
|
|
// Apache logs rotation
|
|
shell_exec('logrotate -f /etc/logrotate.d/apache2 2>&1');
|
|
$cleared[] = 'Apache logs rotated';
|
|
|
|
$response = ['success' => true, 'cleared' => $cleared];
|
|
break;
|
|
|
|
// ==================== ZOMBIE KILLER ====================
|
|
case 'kill_zombies':
|
|
$killed = [];
|
|
|
|
// 1. Find zombie PMTA servers (in DB as running but actually stopped)
|
|
$runningInDb = $db->query("SELECT id, name, ip_address, cloud_instance_id, cloud_provider
|
|
FROM mta.servers WHERE provider_status = 'running'")->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
foreach ($runningInDb as $srv) {
|
|
// Check if really running (port 25)
|
|
$conn = @fsockopen($srv['ip_address'], 25, $errno, $errstr, 3);
|
|
if ($conn === false) {
|
|
// It's a zombie!
|
|
$db->prepare("UPDATE mta.servers SET provider_status = 'zombie_detected' WHERE id = ?")
|
|
->execute([$srv['id']]);
|
|
$killed[] = ['type' => 'pmta_zombie', 'server' => $srv['name'], 'ip' => $srv['ip_address']];
|
|
|
|
// Try to stop at cloud level
|
|
// (would call Huawei/Scaleway API here)
|
|
} else {
|
|
fclose($conn);
|
|
}
|
|
}
|
|
|
|
// 2. Find zombie processes on this server
|
|
$zombieProcesses = shell_exec("ps aux | grep -E 'Z|defunct' | grep -v grep | wc -l");
|
|
if (intval(trim($zombieProcesses)) > 0) {
|
|
// Kill parent processes of zombies
|
|
shell_exec("ps -ef | grep defunct | grep -v grep | awk '{print $3}' | xargs -r kill -9 2>/dev/null");
|
|
$killed[] = ['type' => 'local_zombie', 'count' => intval(trim($zombieProcesses))];
|
|
}
|
|
|
|
// 3. Find stuck PHP processes
|
|
$stuckPhp = shell_exec("ps aux | grep 'php' | grep -v grep | awk '\$10 > 300 {print \$2}'");
|
|
$stuckPids = array_filter(explode("\n", trim($stuckPhp)));
|
|
foreach ($stuckPids as $pid) {
|
|
shell_exec("kill -9 $pid 2>/dev/null");
|
|
$killed[] = ['type' => 'stuck_php', 'pid' => $pid];
|
|
}
|
|
|
|
// 4. Find orphan Apache workers
|
|
$orphanApache = shell_exec("ps aux | grep apache2 | grep -v grep | awk '\$6 > 500000 {print \$2}'"); // >500MB
|
|
$orphanPids = array_filter(explode("\n", trim($orphanApache)));
|
|
foreach ($orphanPids as $pid) {
|
|
shell_exec("kill -9 $pid 2>/dev/null");
|
|
$killed[] = ['type' => 'orphan_apache', 'pid' => $pid];
|
|
}
|
|
|
|
// Log
|
|
$db->prepare("INSERT INTO admin.orchestrator_log (source, action, data, status) VALUES ('zombie-killer', 'kill_zombies', ?, 'success')")
|
|
->execute([json_encode($killed)]);
|
|
|
|
$response = ['success' => true, 'killed' => $killed, 'count' => count($killed)];
|
|
break;
|
|
|
|
// ==================== TRACKING SYSTEM MONITOR ====================
|
|
case 'check_tracking':
|
|
$trackingServers = [
|
|
['name' => 'OVH Tracking 1', 'ip' => '151.80.235.110', 'port' => 80],
|
|
['name' => 'OVH Tracking 2', 'ip' => '151.80.235.111', 'port' => 80],
|
|
['name' => 'Local Tracking', 'ip' => '127.0.0.1', 'port' => 58421],
|
|
];
|
|
|
|
$results = [];
|
|
foreach ($trackingServers as $srv) {
|
|
$conn = @fsockopen($srv['ip'], $srv['port'], $errno, $errstr, 5);
|
|
$isUp = ($conn !== false);
|
|
if ($conn) fclose($conn);
|
|
|
|
// Test tracking endpoint
|
|
$testUrl = "http://{$srv['ip']}:{$srv['port']}/track/test";
|
|
$ch = curl_init($testUrl);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
|
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
|
$trackResponse = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
$results[] = [
|
|
'name' => $srv['name'],
|
|
'ip' => $srv['ip'],
|
|
'port' => $srv['port'],
|
|
'port_open' => $isUp,
|
|
'http_code' => $httpCode,
|
|
'healthy' => $isUp && $httpCode < 400
|
|
];
|
|
}
|
|
|
|
$unhealthy = array_filter($results, fn($r) => !$r['healthy']);
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'servers' => $results,
|
|
'all_healthy' => empty($unhealthy),
|
|
'unhealthy_count' => count($unhealthy)
|
|
];
|
|
break;
|
|
|
|
// ==================== REPAIR TRACKING ====================
|
|
case 'repair_tracking':
|
|
$server = $_POST['server'] ?? 'local';
|
|
$repairs = [];
|
|
|
|
if ($server == 'local' || $server == 'all') {
|
|
// Restart local tracking
|
|
shell_exec('systemctl restart apache2 2>&1');
|
|
$repairs[] = 'Apache restarted (local tracking)';
|
|
|
|
// Check nginx for tracking
|
|
$nginxStatus = trim(shell_exec('systemctl is-active nginx 2>/dev/null'));
|
|
if ($nginxStatus !== 'active') {
|
|
shell_exec('systemctl start nginx 2>&1');
|
|
$repairs[] = 'Nginx started';
|
|
}
|
|
}
|
|
|
|
$response = ['success' => true, 'repairs' => $repairs];
|
|
break;
|
|
|
|
// ==================== URL VALIDATION MATRIX ====================
|
|
case 'validate_send_urls':
|
|
$config_id = intval($_POST['config_id'] ?? $_GET['config_id'] ?? 0);
|
|
|
|
if (!$config_id) {
|
|
$response = ['success' => false, 'error' => 'config_id required'];
|
|
break;
|
|
}
|
|
|
|
$config = $db->query("SELECT c.*, s.image_base_url, s.tracking_domain, o.offer_url
|
|
FROM admin.send_configs c
|
|
LEFT JOIN admin.sponsors s ON c.sponsor_id = s.id
|
|
LEFT JOIN admin.offers o ON c.offer_id = o.id
|
|
WHERE c.id = $config_id")->fetch(PDO::FETCH_ASSOC);
|
|
|
|
$validation = [
|
|
'config_id' => $config_id,
|
|
'tests' => []
|
|
];
|
|
|
|
// 1. Test Image URL
|
|
if ($config['image_url']) {
|
|
$ch = curl_init($config['image_url']);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
|
curl_setopt($ch, CURLOPT_NOBODY, true);
|
|
curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
|
curl_close($ch);
|
|
|
|
$validation['tests']['image'] = [
|
|
'url' => $config['image_url'],
|
|
'status' => $httpCode,
|
|
'content_type' => $contentType,
|
|
'ok' => $httpCode == 200 && strpos($contentType, 'image') !== false
|
|
];
|
|
}
|
|
|
|
// 2. Test Tracking Domain
|
|
if ($config['tracking_domain']) {
|
|
$trackUrl = "https://{$config['tracking_domain']}/health";
|
|
$ch = curl_init($trackUrl);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
$validation['tests']['tracking_domain'] = [
|
|
'url' => $trackUrl,
|
|
'status' => $httpCode,
|
|
'ok' => $httpCode >= 200 && $httpCode < 400
|
|
];
|
|
}
|
|
|
|
// 3. Test Tracking Link Redirect
|
|
if ($config['tracking_domain'] && $config['offer_url']) {
|
|
$trackLink = "https://{$config['tracking_domain']}/c/test123";
|
|
$ch = curl_init($trackLink);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$redirectUrl = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
|
|
curl_close($ch);
|
|
|
|
$validation['tests']['tracking_redirect'] = [
|
|
'url' => $trackLink,
|
|
'status' => $httpCode,
|
|
'redirect_to' => $redirectUrl,
|
|
'ok' => $httpCode == 301 || $httpCode == 302
|
|
];
|
|
}
|
|
|
|
// 4. Test Offer URL
|
|
if ($config['offer_url']) {
|
|
$ch = curl_init($config['offer_url']);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
|
|
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
|
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$finalUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
|
|
curl_close($ch);
|
|
|
|
$validation['tests']['offer_url'] = [
|
|
'url' => $config['offer_url'],
|
|
'final_url' => $finalUrl,
|
|
'status' => $httpCode,
|
|
'ok' => $httpCode >= 200 && $httpCode < 400
|
|
];
|
|
}
|
|
|
|
// Overall status
|
|
$allOk = true;
|
|
foreach ($validation['tests'] as $test) {
|
|
if (!$test['ok']) $allOk = false;
|
|
}
|
|
$validation['all_ok'] = $allOk;
|
|
|
|
$response = ['success' => true, 'validation' => $validation];
|
|
break;
|
|
|
|
// ==================== FULL SEND TEST ====================
|
|
case 'full_send_test':
|
|
$config_id = intval($_POST['config_id'] ?? 0);
|
|
|
|
$results = [
|
|
'config_id' => $config_id,
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
|
'tests' => []
|
|
];
|
|
|
|
// 1. URL Validation
|
|
$urlValidation = json_decode(file_get_contents("http://127.0.0.1:5821/api/master-monitor-api.php?action=validate_send_urls&config_id=$config_id"), true);
|
|
$results['tests']['urls'] = $urlValidation['validation'] ?? ['ok' => false];
|
|
|
|
// 2. Seed Test (if seeds available)
|
|
$seedCount = $db->query("SELECT COUNT(*) FROM admin.seed_accounts WHERE status = 'active'")->fetchColumn();
|
|
$results['tests']['seeds'] = [
|
|
'available' => $seedCount,
|
|
'ok' => $seedCount > 0
|
|
];
|
|
|
|
// 3. Server Availability
|
|
$config = $db->query("SELECT server_ids FROM admin.send_configs WHERE id = $config_id")->fetch(PDO::FETCH_ASSOC);
|
|
$serverIds = trim($config['server_ids'] ?? '', '{}');
|
|
|
|
if ($serverIds) {
|
|
$servers = $db->query("SELECT id, ip_address, provider_status FROM mta.servers WHERE id IN ($serverIds)")->fetchAll(PDO::FETCH_ASSOC);
|
|
$serversOk = 0;
|
|
foreach ($servers as $s) {
|
|
if ($s['provider_status'] == 'running') {
|
|
$conn = @fsockopen($s['ip_address'], 25, $errno, $errstr, 3);
|
|
if ($conn) {
|
|
fclose($conn);
|
|
$serversOk++;
|
|
}
|
|
}
|
|
}
|
|
$results['tests']['servers'] = [
|
|
'total' => count($servers),
|
|
'running' => $serversOk,
|
|
'ok' => $serversOk > 0
|
|
];
|
|
}
|
|
|
|
// 4. Suppression Check
|
|
$suppressionDone = $db->query("SELECT suppression_done FROM admin.send_configs WHERE id = $config_id")->fetchColumn();
|
|
$results['tests']['suppression'] = [
|
|
'done' => (bool)$suppressionDone,
|
|
'ok' => (bool)$suppressionDone
|
|
];
|
|
|
|
// Overall
|
|
$allOk = true;
|
|
foreach ($results['tests'] as $test) {
|
|
if (!($test['ok'] ?? false)) $allOk = false;
|
|
}
|
|
$results['all_ok'] = $allOk;
|
|
$results['ready_to_send'] = $allOk;
|
|
|
|
$response = ['success' => true, 'results' => $results];
|
|
break;
|
|
|
|
// ==================== REGRESSION DETECTION ====================
|
|
case 'detect_regressions':
|
|
$regressions = [];
|
|
|
|
// Compare current error counts with yesterday
|
|
$todayErrors = intval(shell_exec("grep -c 'error' /var/log/apache2/error.log 2>/dev/null || echo 0"));
|
|
$yesterdayErrors = intval(shell_exec("grep -c 'error' /var/log/apache2/error.log.1 2>/dev/null || echo 0"));
|
|
|
|
if ($todayErrors > $yesterdayErrors * 2 && $todayErrors > 10) {
|
|
$regressions[] = [
|
|
'type' => 'error_spike',
|
|
'today' => $todayErrors,
|
|
'yesterday' => $yesterdayErrors,
|
|
'increase' => round(($todayErrors / max(1, $yesterdayErrors)) * 100 - 100, 1) . '%'
|
|
];
|
|
}
|
|
|
|
// Check for new 500 errors in last hour
|
|
$recent500 = shell_exec("grep '500' /var/log/apache2/error.log 2>/dev/null | tail -100 | grep -c \"$(date '+%b %d %H')\" || echo 0");
|
|
if (intval(trim($recent500)) > 5) {
|
|
$regressions[] = [
|
|
'type' => '500_errors',
|
|
'count' => intval(trim($recent500)),
|
|
'period' => 'last_hour'
|
|
];
|
|
}
|
|
|
|
// Check for new PHP files with syntax errors
|
|
$syntaxErrors = shell_exec("find /opt/wevads/public -name '*.php' -mmin -60 -exec php -l {} \; 2>&1 | grep -c 'Parse error' || echo 0");
|
|
if (intval(trim($syntaxErrors)) > 0) {
|
|
$regressions[] = [
|
|
'type' => 'php_syntax_error',
|
|
'count' => intval(trim($syntaxErrors))
|
|
];
|
|
}
|
|
|
|
// Check AI provider health
|
|
$failedProviders = $db->query("SELECT COUNT(*) FROM admin.ai_providers WHERE status = 'error'")->fetchColumn();
|
|
if ($failedProviders > 3) {
|
|
$regressions[] = [
|
|
'type' => 'ai_providers_down',
|
|
'count' => $failedProviders
|
|
];
|
|
}
|
|
|
|
$response = [
|
|
'success' => true,
|
|
'regressions' => $regressions,
|
|
'count' => count($regressions),
|
|
'critical' => count($regressions) > 2
|
|
];
|
|
break;
|
|
}
|
|
|
|
echo json_encode($response, JSON_PRETTY_PRINT);
|
|
|