Files
wevads-platform/public/hamid-api.php.before_brain
2026-02-26 04:53:11 +01:00

372 lines
14 KiB
Plaintext
Executable File

<?php
header('Content-Type: application/json');
error_reporting(0);
try {
$input = json_decode(file_get_contents('php://input'), true);
if (!$input || (!isset($input['message']) && !isset($input['action']))) {
echo json_encode(['error' => 'Message requis']);
exit;
}
$message = $input['message'];
$history = $input['history'] ?? [];
$provider = $input['provider'] ?? 'cerebras';
$pdo = new PDO("pgsql:host=localhost;dbname=adx_system", "admin", "admin123");
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// Handler actions speciales
if (isset($input["action"])) {
if ($input["action"] === "list_conversations") {
$stmt = $pdo->query("SELECT id, title, created_at, updated_at FROM admin.hamid_conversations ORDER BY updated_at DESC LIMIT 20");
echo json_encode(["conversations" => $stmt->fetchAll(PDO::FETCH_ASSOC)]);
exit;
}
}
// Récupérer config
$config = [];
try {
$stmt = $pdo->query("SELECT config_key, config_value FROM admin.hamid_config");
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$config[$row['config_key']] = $row['config_value'];
}
} catch (Exception $e) {}
// ============================================
// RECHERCHE KNOWLEDGE BASE - AMÉLIORÉE
// ============================================
$kbContext = "";
$kbCount = 0;
$kbTitles = [];
try {
// Extraire les mots-clés du message (mots de plus de 3 caractères)
$words = preg_split('/\s+/', strtolower($message));
$keywords = array_filter($words, function($w) {
return strlen($w) > 3 && !in_array($w, ['pour', 'dans', 'avec', 'cette', 'faire', 'comment', 'quoi', 'quel', 'quelle', 'sont', 'est-ce', 'peux', 'veux', 'dois']);
});
if (!empty($keywords)) {
// Recherche par mots-clés
$conditions = [];
$params = [];
foreach ($keywords as $i => $kw) {
$conditions[] = "(LOWER(title) LIKE ? OR LOWER(content) LIKE ?)";
$params[] = '%' . $kw . '%';
$params[] = '%' . $kw . '%';
}
$sql = "SELECT id, question as title, answer as content FROM admin.commonia_knowledge WHERE " . implode(' OR ', $conditions) . " LIMIT 8";
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$kbContext .= "\n\n### " . $row['title'] . " ###\n" . mb_substr($row['content'], 0, 500);
$kbTitles[] = $row['title'];
$kbCount++;
}
}
// Si pas de résultats avec mots-clés, recherche générale
if ($kbCount == 0) {
$stmt = $pdo->prepare("SELECT id, question as title, answer as content FROM admin.commonia_knowledge WHERE LOWER(content) LIKE ? OR LOWER(question) LIKE ? LIMIT 8");
$searchTerm = '%' . strtolower(substr($message, 0, 50)) . '%';
$stmt->execute([$searchTerm, $searchTerm]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$kbContext .= "\n\n### " . $row['title'] . " ###\n" . mb_substr($row['content'], 0, 500);
$kbTitles[] = $row['title'];
$kbCount++;
}
}
} catch (Exception $e) {
// Log error but continue
error_log("KB Search Error: " . $e->getMessage());
}
// ============================================
// RECHERCHE MÉMOIRE
// ============================================
$memContext = "";
$memCount = 0;
try {
$stmt = $pdo->prepare("SELECT key, value FROM admin.chatbot_memory WHERE LOWER(key) LIKE ? OR LOWER(value) LIKE ? LIMIT 8");
$searchTerm = '%' . strtolower($message) . '%';
$stmt->execute([$searchTerm, $searchTerm]);
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$memContext .= "\n[" . $row['key'] . "]: " . $row['value'];
$memCount++;
}
} catch (Exception $e) {}
// ============================================
// SYSTEM PROMPT AVEC CONTEXTE KB
// ============================================
$systemPrompt = $config['system_prompt'] ?? "Tu es HAMID, un assistant IA expert pour WEVADS, FMGAPP et BCGAPP. Tu aides avec l'architecture système, le développement, l'email marketing, et les questions techniques. Réponds en français de manière claire et professionnelle.";
// IMPORTANT: Ajouter le contexte KB au prompt
if ($kbContext) {
$systemPrompt .= "\n\n=== KNOWLEDGE BASE (utilise ces informations pour répondre) ===\n" . $kbContext . "\n=== FIN KNOWLEDGE BASE ===";
}
if ($memContext) {
$systemPrompt .= "\n\n=== MÉMOIRE UTILISATEUR ===\n" . $memContext . "\n=== FIN MÉMOIRE ===";
}
// ============================================
// PROVIDERS
// ============================================
$providers = [
'cerebras' => [
'url' => 'https://api.cerebras.ai/v1/chat/completions',
'key' => $config['cerebras_api_key'] ?? '',
'model' => 'llama3.1-8b'
],
'groq' => [
'url' => 'https://api.groq.com/openai/v1/chat/completions',
'key' => $config['groq_api_key'] ?? '',
'model' => 'llama-3.3-70b-versatile'
],
'deepseek' => [
'url' => 'https://api.deepseek.com/v1/chat/completions',
'key' => $config['deepseek_api_key'] ?? '',
'model' => 'deepseek-chat'
],
'gemini' => [
'url' => 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent',
'key' => $config['gemini_api_key'] ?? '',
'model' => 'gemini-2.0-flash'
],
'chatgpt' => [
'url' => 'https://api.openai.com/v1/chat/completions',
'key' => $config['openai_api_key'] ?? '',
'model' => 'gpt-4o-mini'
],
'claude' => [
'url' => 'https://api.anthropic.com/v1/messages',
'key' => $config['claude_api_key'] ?? '',
'model' => 'claude-3-haiku-20240307'
],
'hyperbolic' => [
'url' => 'https://api.hyperbolic.xyz/v1/chat/completions',
'key' => $config['hyperbolic_api_key'] ?? '',
'model' => 'meta-llama/Llama-3.3-70B-Instruct'
],
'mistral' => [
'url' => 'https://api.mistral.ai/v1/chat/completions',
'key' => $config['mistral_api_key'] ?? '',
'model' => 'mistral-small-latest'
],
'cohere' => [
'url' => 'https://api.cohere.ai/v1/chat',
'key' => $config['cohere_api_key'] ?? '',
'model' => 'command-r'
],
'sambanova' => [
'url' => 'https://api.sambanova.ai/v1/chat/completions',
'key' => $config['sambanova_api_key'] ?? '',
'model' => 'Meta-Llama-3.1-8B-Instruct'
],
'ollama' => [
'url' => ($config['ollama_url'] ?? 'http://localhost:11434') . '/api/chat',
'key' => '',
'model' => $config['ollama_model'] ?? 'llama3'
],
'ollama-mini' => [
'url' => ($config['ollama_url'] ?? 'http://localhost:11434') . '/api/chat',
'key' => '',
'model' => 'llama3.2:1b'
]
];
$providerConfig = $providers[$provider] ?? $providers['cerebras'];
if (empty($providerConfig['key']) && !in_array($provider, ['ollama', 'ollama-mini'])) {
echo json_encode([
'error' => "Clé API non configurée pour $provider",
'provider' => $provider,
'kb_count' => $kbCount,
'mem_count' => $memCount
]);
exit;
}
// Build messages
$messages = [['role' => 'system', 'content' => $systemPrompt]];
foreach ($history as $msg) {
if (isset($msg['role']) && isset($msg['content'])) {
$messages[] = ['role' => $msg['role'], 'content' => $msg['content']];
}
}
$messages[] = ['role' => 'user', 'content' => $message];
// API call
$ch = curl_init();
$startTime = microtime(true);
if ($provider === 'gemini') {
$url = $providerConfig['url'] . '?key=' . $providerConfig['key'];
$geminiMessages = array_filter($messages, fn($m) => $m['role'] !== 'system');
$payload = [
'contents' => array_map(function($m) {
return [
'role' => $m['role'] === 'assistant' ? 'model' : 'user',
'parts' => [['text' => $m['content']]]
];
}, array_values($geminiMessages)),
'systemInstruction' => ['parts' => [['text' => $systemPrompt]]]
];
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 60
]);
} elseif ($provider === 'claude') {
$claudeMessages = array_values(array_filter($messages, fn($m) => $m['role'] !== 'system'));
$payload = [
'model' => $providerConfig['model'],
'max_tokens' => 4096,
'system' => $systemPrompt,
'messages' => $claudeMessages
];
curl_setopt_array($ch, [
CURLOPT_URL => $providerConfig['url'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'x-api-key: ' . $providerConfig['key'],
'anthropic-version: 2023-06-01'
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 60
]);
} elseif ($provider === 'cohere') {
$chatHistory = [];
foreach (array_slice($messages, 1, -1) as $m) {
$chatHistory[] = [
'role' => $m['role'] === 'assistant' ? 'CHATBOT' : 'USER',
'message' => $m['content']
];
}
$payload = [
'model' => $providerConfig['model'],
'message' => $message,
'preamble' => $systemPrompt,
'chat_history' => $chatHistory
];
curl_setopt_array($ch, [
CURLOPT_URL => $providerConfig['url'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $providerConfig['key']
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 60
]);
} elseif (in_array($provider, ['ollama', 'ollama-mini'])) {
$payload = [
'model' => $providerConfig['model'],
'messages' => $messages,
'stream' => false
];
curl_setopt_array($ch, [
CURLOPT_URL => $providerConfig['url'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 120
]);
} else {
// OpenAI-compatible
$payload = [
'model' => $providerConfig['model'],
'messages' => $messages,
'max_tokens' => 4096,
'temperature' => 0.7
];
curl_setopt_array($ch, [
CURLOPT_URL => $providerConfig['url'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $providerConfig['key']
],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_TIMEOUT => 60
]);
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
$duration = round((microtime(true) - $startTime) * 1000);
if ($curlError) {
echo json_encode(['error' => "Erreur connexion: $curlError", 'provider' => $provider, 'kb_count' => $kbCount]);
exit;
}
$data = json_decode($response, true);
if ($httpCode !== 200) {
$errorMsg = $data['error']['message'] ?? $data['error'] ?? $response;
echo json_encode(['error' => "Erreur API ($httpCode): $errorMsg", 'provider' => $provider, 'kb_count' => $kbCount]);
exit;
}
// Extract response
$aiResponse = '';
if ($provider === 'gemini') {
$aiResponse = $data['candidates'][0]['content']['parts'][0]['text'] ?? 'Pas de réponse';
} elseif ($provider === 'claude') {
$aiResponse = $data['content'][0]['text'] ?? 'Pas de réponse';
} elseif ($provider === 'cohere') {
$aiResponse = $data['text'] ?? 'Pas de réponse';
} elseif (in_array($provider, ['ollama', 'ollama-mini'])) {
$aiResponse = $data['message']['content'] ?? 'Pas de réponse';
} else {
$aiResponse = $data['choices'][0]['message']['content'] ?? 'Pas de réponse';
}
// Files
$files = [];
if (preg_match('/\[FILE:([^\]]+)\]/', $aiResponse, $matches)) {
$fileName = trim($matches[1]);
$files[] = [
'name' => $fileName,
'type' => pathinfo($fileName, PATHINFO_EXTENSION),
'url' => '/hamid-files/' . $fileName
];
}
echo json_encode([
'response' => $aiResponse,
'provider' => $provider,
'model' => $providerConfig['model'],
'duration' => $duration,
'kb_count' => $kbCount,
'kb_titles' => $kbTitles,
'mem_count' => $memCount,
'files' => $files
]);
} catch (Exception $e) {
echo json_encode(['error' => 'Erreur serveur: ' . $e->getMessage()]);
}