300 lines
13 KiB
PHP
Executable File
300 lines
13 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* =====================================================
|
|
* WEVAL MIND - INTERNAL AI API v2.0
|
|
* =====================================================
|
|
* 🧠 AI Assistant for WEVAL Marketing Platform
|
|
* ✅ FULL KB ACCESS (141+ documents)
|
|
* Server: 89.167.40.150:5821
|
|
* =====================================================
|
|
*/
|
|
|
|
header('Content-Type: application/json');
|
|
header('Access-Control-Allow-Origin: *');
|
|
header('Access-Control-Allow-Methods: POST, OPTIONS');
|
|
header('Access-Control-Allow-Headers: Content-Type');
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
|
|
http_response_code(200);
|
|
exit;
|
|
}
|
|
|
|
$CONFIG = [
|
|
'db' => ['host' => 'localhost', 'name' => 'adx_system', 'user' => 'admin', 'pass' => 'admin123'],
|
|
'servers' => ['app' => '89.167.40.150', 'tracking' => '151.80.235.110', 'consulting' => '46.62.220.135'],
|
|
'max_tokens' => 4096,
|
|
'temperature' => 0.7,
|
|
'kb_enabled' => true,
|
|
'memory_enabled' => true
|
|
];
|
|
|
|
$PROVIDERS = [
|
|
'cerebras' => ['name' => 'Cerebras', 'endpoint' => 'https://api.cerebras.ai/v1/chat/completions', 'model' => 'llama3.1-70b', 'priority' => 1, 'config_key' => 'cerebras_api_key'],
|
|
'groq' => ['name' => 'Groq', 'endpoint' => 'https://api.groq.com/openai/v1/chat/completions', 'model' => 'llama-3.3-70b-versatile', 'priority' => 2, 'config_key' => 'groq_api_key'],
|
|
'sambanova' => ['name' => 'SambaNova', 'endpoint' => 'https://api.sambanova.ai/v1/chat/completions', 'model' => 'Meta-Llama-3.1-70B-Instruct', 'priority' => 3, 'config_key' => 'sambanova_api_key'],
|
|
'deepseek' => ['name' => 'DeepSeek', 'endpoint' => 'https://api.deepseek.com/v1/chat/completions', 'model' => 'deepseek-chat', 'priority' => 4, 'config_key' => 'deepseek_api_key'],
|
|
'mistral' => ['name' => 'Mistral', 'endpoint' => 'https://api.mistral.ai/v1/chat/completions', 'model' => 'mistral-large-latest', 'priority' => 5, 'config_key' => 'mistral_api_key'],
|
|
'together' => ['name' => 'Together AI', 'endpoint' => 'https://api.together.xyz/v1/chat/completions', 'model' => 'meta-llama/Llama-3-70b-chat-hf', 'priority' => 6, 'config_key' => 'together_api_key'],
|
|
'openrouter' => ['name' => 'OpenRouter', 'endpoint' => 'https://openrouter.ai/api/v1/chat/completions', 'model' => 'meta-llama/llama-3.1-70b-instruct', 'priority' => 7, 'config_key' => 'openrouter_api_key']
|
|
];
|
|
|
|
$SYSTEM_PROMPT = <<<PROMPT
|
|
Tu es WEVAL MIND, l'assistant IA intelligent de la plateforme WEVAL Marketing.
|
|
|
|
- WEVAL Consulting (weval-consulting.com) - Conseil IT, Recrutement, Marketing Digital
|
|
- WEVAL Marketing (cette plateforme) - Infrastructure Email Marketing & Automation
|
|
|
|
- Serveur App Principal: 89.167.40.150:5821 (Hetzner, Ubuntu)
|
|
- Serveur Tracking: 151.80.235.110 (OVH)
|
|
- Serveur Consulting: 46.62.220.135 (Hetzner)
|
|
- Base de données: PostgreSQL adx_system (admin/admin123)
|
|
- Schémas DB: admin, clients, mta, automation, leads
|
|
|
|
- PowerMTA: Versions 4.0r8, 4.5r8, 5.0r1, 5.0r3
|
|
- Office 365: 1,352 comptes actifs, 1,182 domaines
|
|
- Brain Engine: 51,246 seeds pour auto-learning
|
|
- Offers actives: 32 offres affiliées, 344 créatives
|
|
|
|
WEVAL MIND (IA), WEVAL SEND (Delivery), WEVAL TRACK (Analytics), WEVAL CLOUD (Infrastructure), WEVAL DNS (Domaines), WEVAL CONNECT (O365), WEVAL STUDIO (Templates), WEVAL DATA (Listes), WEVAL ADS (Affiliés), WEVAL PULSE (Monitoring)
|
|
|
|
PROMPT;
|
|
|
|
function getDB() {
|
|
global $CONFIG;
|
|
static $pdo = null;
|
|
if ($pdo === null) {
|
|
try {
|
|
$pdo = new PDO("pgsql:host={$CONFIG['db']['host']};dbname={$CONFIG['db']['name']}",
|
|
$CONFIG['db']['user'], $CONFIG['db']['pass'],
|
|
[PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC]);
|
|
} catch (Exception $e) { return null; }
|
|
}
|
|
return $pdo;
|
|
}
|
|
|
|
function getApiKey($configKey) {
|
|
$pdo = getDB();
|
|
if (!$pdo) return null;
|
|
try {
|
|
$stmt = $pdo->prepare("SELECT config_value FROM admin.hamid_config WHERE config_key = ? AND status = 'active' LIMIT 1");
|
|
$stmt->execute([$configKey]);
|
|
$result = $stmt->fetch();
|
|
if ($result) return $result['config_value'];
|
|
$stmt = $pdo->prepare("SELECT config_value FROM admin.commonia_config WHERE config_key = ? LIMIT 1");
|
|
$stmt->execute([$configKey]);
|
|
$result = $stmt->fetch();
|
|
return $result ? $result['config_value'] : null;
|
|
} catch (Exception $e) { return null; }
|
|
}
|
|
|
|
function searchKB($query, $limit = 5) {
|
|
$pdo = getDB();
|
|
if (!$pdo) return [];
|
|
try {
|
|
$stmt = $pdo->prepare("SELECT title, content, category FROM admin.knowledge_base WHERE content ILIKE ? OR title ILIKE ? LIMIT ?");
|
|
$searchTerm = "%{$query}%";
|
|
$stmt->execute([$searchTerm, $searchTerm, $limit]);
|
|
return $stmt->fetchAll();
|
|
} catch (Exception $e) { return []; }
|
|
}
|
|
|
|
function saveToMemory($sessionId, $role, $content) {
|
|
global $CONFIG;
|
|
if (!$CONFIG['memory_enabled']) return;
|
|
$pdo = getDB();
|
|
if (!$pdo) return;
|
|
try {
|
|
$stmt = $pdo->prepare("INSERT INTO admin.weval_mind_conversations (session_id, role, content, created_at) VALUES (?, ?, ?, NOW())");
|
|
$stmt->execute([$sessionId, $role, $content]);
|
|
} catch (Exception $e) {}
|
|
}
|
|
|
|
function getConversationHistory($sessionId, $limit = 10) {
|
|
global $CONFIG;
|
|
if (!$CONFIG['memory_enabled']) return [];
|
|
$pdo = getDB();
|
|
if (!$pdo) return [];
|
|
try {
|
|
$stmt = $pdo->prepare("SELECT role, content FROM admin.weval_mind_conversations WHERE session_id = ? ORDER BY created_at DESC LIMIT ?");
|
|
$stmt->execute([$sessionId, $limit]);
|
|
return array_reverse($stmt->fetchAll());
|
|
} catch (Exception $e) { return []; }
|
|
}
|
|
|
|
function callProvider($providerKey, $messages, $options = []) {
|
|
global $PROVIDERS, $CONFIG;
|
|
$provider = $PROVIDERS[$providerKey] ?? null;
|
|
if (!$provider) return ['success' => false, 'error' => 'Provider not found'];
|
|
|
|
$apiKey = getApiKey($provider['config_key']);
|
|
if (!$apiKey) return ['success' => false, 'error' => 'API key not configured'];
|
|
|
|
$payload = [
|
|
'model' => $options['model'] ?? $provider['model'],
|
|
'messages' => $messages,
|
|
'max_tokens' => $options['max_tokens'] ?? $CONFIG['max_tokens'],
|
|
'temperature' => $options['temperature'] ?? $CONFIG['temperature'],
|
|
'stream' => false
|
|
];
|
|
|
|
$headers = ['Content-Type: application/json', 'Authorization: Bearer ' . $apiKey];
|
|
if ($providerKey === 'openrouter') {
|
|
$headers[] = 'HTTP-Referer: https://weval-consulting.com';
|
|
$headers[] = 'X-Title: WEVAL MIND';
|
|
}
|
|
|
|
$ch = curl_init($provider['endpoint']);
|
|
curl_setopt_array($ch, [
|
|
CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true,
|
|
CURLOPT_HTTPHEADER => $headers, CURLOPT_POSTFIELDS => json_encode($payload),
|
|
CURLOPT_TIMEOUT => 60, CURLOPT_CONNECTTIMEOUT => 10
|
|
]);
|
|
|
|
$startTime = microtime(true);
|
|
$response = curl_exec($ch);
|
|
$duration = round((microtime(true) - $startTime) * 1000);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
$error = curl_error($ch);
|
|
curl_close($ch);
|
|
|
|
if ($error) return ['success' => false, 'error' => "cURL: $error", 'provider' => $providerKey];
|
|
if ($httpCode !== 200) return ['success' => false, 'error' => "HTTP $httpCode", 'provider' => $providerKey];
|
|
|
|
$data = json_decode($response, true);
|
|
if (!$data || !isset($data['choices'][0]['message']['content'])) {
|
|
return ['success' => false, 'error' => 'Invalid response', 'provider' => $providerKey];
|
|
}
|
|
|
|
return [
|
|
'success' => true, 'content' => $data['choices'][0]['message']['content'],
|
|
'provider' => $providerKey, 'provider_name' => $provider['name'],
|
|
'model' => $payload['model'], 'duration_ms' => $duration
|
|
];
|
|
}
|
|
|
|
function callWithFailover($messages, $options = []) {
|
|
global $PROVIDERS;
|
|
$sorted = $PROVIDERS;
|
|
uasort($sorted, fn($a, $b) => $a['priority'] <=> $b['priority']);
|
|
$preferredProvider = $options['provider'] ?? null;
|
|
$errors = [];
|
|
|
|
if ($preferredProvider && isset($PROVIDERS[$preferredProvider])) {
|
|
$result = callProvider($preferredProvider, $messages, $options);
|
|
if ($result['success']) return $result;
|
|
$errors[$preferredProvider] = $result['error'];
|
|
}
|
|
|
|
foreach ($sorted as $key => $provider) {
|
|
if ($key === $preferredProvider) continue;
|
|
$result = callProvider($key, $messages, $options);
|
|
if ($result['success']) return $result;
|
|
$errors[$key] = $result['error'];
|
|
}
|
|
|
|
return ['success' => false, 'error' => 'All providers failed', 'details' => $errors];
|
|
}
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
|
|
echo json_encode(['success' => false, 'error' => 'POST method required']);
|
|
exit;
|
|
}
|
|
|
|
$input = json_decode(file_get_contents('php://input'), true);
|
|
if (!$input) $input = $_POST;
|
|
$action = $input['action'] ?? 'chat';
|
|
|
|
switch ($action) {
|
|
case 'chat':
|
|
$message = trim($input['message'] ?? '');
|
|
$sessionId = $input['session_id'] ?? session_id();
|
|
$provider = $input['provider'] ?? null;
|
|
$includeKB = $input['include_kb'] ?? true;
|
|
|
|
if (empty($message)) {
|
|
echo json_encode(['success' => false, 'error' => 'Message required']);
|
|
exit;
|
|
}
|
|
|
|
$messages = [['role' => 'system', 'content' => $SYSTEM_PROMPT]];
|
|
|
|
if ($includeKB && $CONFIG['kb_enabled']) {
|
|
$kbResults = searchKB($message, 3);
|
|
if (!empty($kbResults)) {
|
|
$kbContext = "\n\n📚 Contexte KB:\n";
|
|
foreach ($kbResults as $doc) {
|
|
$kbContext .= "- [{$doc['category']}] {$doc['title']}: " . substr($doc['content'], 0, 500) . "...\n";
|
|
}
|
|
$messages[0]['content'] .= $kbContext;
|
|
}
|
|
}
|
|
|
|
$history = getConversationHistory($sessionId, 10);
|
|
foreach ($history as $h) {
|
|
$messages[] = ['role' => $h['role'], 'content' => $h['content']];
|
|
}
|
|
$messages[] = ['role' => 'user', 'content' => $message];
|
|
|
|
$result = callWithFailover($messages, ['provider' => $provider]);
|
|
|
|
if ($result['success']) {
|
|
saveToMemory($sessionId, 'user', $message);
|
|
saveToMemory($sessionId, 'assistant', $result['content']);
|
|
echo json_encode([
|
|
'success' => true, 'response' => $result['content'],
|
|
'provider' => $result['provider_name'], 'model' => $result['model'],
|
|
'duration_ms' => $result['duration_ms'], 'session_id' => $sessionId
|
|
]);
|
|
} else {
|
|
echo json_encode($result);
|
|
}
|
|
break;
|
|
|
|
case 'providers':
|
|
$providers = [];
|
|
foreach ($PROVIDERS as $key => $p) {
|
|
$hasKey = getApiKey($p['config_key']) !== null;
|
|
$providers[$key] = ['name' => $p['name'], 'model' => $p['model'], 'priority' => $p['priority'], 'available' => $hasKey];
|
|
}
|
|
echo json_encode(['success' => true, 'providers' => $providers]);
|
|
break;
|
|
|
|
case 'kb_search':
|
|
$query = trim($input['query'] ?? '');
|
|
$limit = min(20, max(1, intval($input['limit'] ?? 5)));
|
|
if (empty($query)) { echo json_encode(['success' => false, 'error' => 'Query required']); exit; }
|
|
$results = searchKB($query, $limit);
|
|
echo json_encode(['success' => true, 'results' => $results, 'count' => count($results)]);
|
|
break;
|
|
|
|
case 'stats':
|
|
$pdo = getDB();
|
|
$stats = [];
|
|
if ($pdo) {
|
|
try {
|
|
$stats['mta_servers'] = $pdo->query("SELECT COUNT(*) FROM admin.mta_servers WHERE status = 'active'")->fetchColumn();
|
|
$stats['smtp_accounts'] = $pdo->query("SELECT COUNT(*) FROM admin.smtp_accounts WHERE status = 'active'")->fetchColumn();
|
|
$stats['domains'] = $pdo->query("SELECT COUNT(*) FROM admin.domains WHERE status = 'active'")->fetchColumn();
|
|
$stats['kb_docs'] = $pdo->query("SELECT COUNT(*) FROM admin.knowledge_base")->fetchColumn();
|
|
} catch (Exception $e) {}
|
|
}
|
|
echo json_encode(['success' => true, 'stats' => $stats]);
|
|
break;
|
|
|
|
case 'clear_history':
|
|
$sessionId = $input['session_id'] ?? session_id();
|
|
$pdo = getDB();
|
|
if ($pdo) {
|
|
try {
|
|
$stmt = $pdo->prepare("DELETE FROM admin.weval_mind_conversations WHERE session_id = ?");
|
|
$stmt->execute([$sessionId]);
|
|
echo json_encode(['success' => true]);
|
|
} catch (Exception $e) { echo json_encode(['success' => false, 'error' => $e->getMessage()]); }
|
|
}
|
|
break;
|
|
|
|
default:
|
|
echo json_encode(['success' => false, 'error' => 'Unknown action']);
|
|
}
|
|
|