configFile = $configFile; } //$this->configFile = $configFile; $this->apiKey = $apiKey; } /** * Appel API générique */ private function apiCall($method, $endpoint, $data = null) { if (empty($endpoint)) { throw new Exception("Endpoint vide"); } $url = $this->baseUrl . $endpoint; $ch = curl_init(); if ($ch === false) { throw new Exception("Impossible d'initialiser cURL"); } curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Authorization: Bearer ' . $this->apiKey, 'OpenAI-Beta: assistants=v2' ]); if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); if ($data) { curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); } } $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { throw new Exception("Erreur cURL: $error"); } if ($httpCode >= 400) { throw new Exception("Erreur API ($httpCode): " . substr($response, 0, 300)); } $decoded = json_decode($response, true); if ($decoded === null) { throw new Exception("Réponse JSON invalide: " . substr($response, 0, 200)); } return $decoded; } /** * Charger la configuration */ private function loadConfig() { if (file_exists($this->configFile)) { $content = file_get_contents($this->configFile); $config = json_decode($content, true); return $config ?: ['assistant_id' => null, 'threads' => []]; } return ['assistant_id' => null, 'threads' => []]; } /** * Sauvegarder la configuration */ private function saveConfig($config) { if (empty($this->configFile)) { throw new Exception("Chemin du fichier de config vide"); } // Créer le dossier parent si nécessaire $dir = dirname($this->configFile); if (!is_dir($dir)) { mkdir($dir, 0755, true); } $json = json_encode($config, JSON_PRETTY_PRINT); $result = file_put_contents($this->configFile, $json); if ($result === false) { throw new Exception("Impossible d'écrire dans: " . $this->configFile); } return true; } /** * Créer un assistant */ public function createAssistant($name, $instructions, $model = null) { if ($model === null) { $model = $this->model; } return $this->apiCall('POST', '/assistants', [ 'name' => $name, 'instructions' => $instructions, 'model' => $model ]); } /** * Créer un thread */ public function createThread() { return $this->apiCall('POST', '/threads'); } /** * Ajouter un message à un thread */ public function addMessage($threadId, $content) { return $this->apiCall('POST', "/threads/$threadId/messages", [ 'role' => 'user', 'content' => $content ]); } /** * Exécuter l'assistant */ public function runAssistant($threadId, $assistantId) { echo "runAssistant\n"; $run = $this->apiCall('POST', "/threads/$threadId/runs", [ 'assistant_id' => $assistantId ]); return $this->waitForRunCompletion($threadId, $run['id']); } /** * Attendre la fin de l'exécution */ private function waitForRunCompletion($threadId, $runId, $maxAttempts = 30) { for ($i = 0; $i < $maxAttempts; $i++) { $run = $this->apiCall('GET', "/threads/$threadId/runs/$runId"); if ($run['status'] === 'completed') { echo "run complete after ".$i." attempts\n"; return $run; } if (in_array($run['status'], ['failed', 'cancelled', 'expired'])) { //echo "Run : ".print_r($run, true)."\n"; throw new Exception("Run échoué: (" . $run['status'].") : ".$run['message']); } sleep(1); } throw new Exception("Timeout en attendant la réponse"); } /** * Récupérer les messages */ public function getMessages($threadId, $limit = 1) { $response = $this->apiCall('GET', "/threads/$threadId/messages?limit=$limit"); return $response['data']; } /** * Obtenir ou créer l'assistant */ public function getOrCreateAssistant($name, $instructions, $model = null) { if ($model === null) { $model = $this->model; } $config = $this->loadConfig(); if (!empty($config['assistant_id'])) { echo "get existing assistant ".$config['assistant_id']."\n"; return $config['assistant_id']; } $assistant = $this->createAssistant($name, $instructions, $model); $config['assistant_id'] = $assistant['id']; $this->saveConfig($config); echo "get new assistant ".$assistant['id']."\n"; return $assistant['id']; } /** * Obtenir ou créer un thread pour une pièce */ public function getOrCreateThread($profile) { $config = $this->loadConfig(); if (!empty($config['threads'][$profile])) { return $config['threads'][$profile]; } $thread = $this->createThread(); $config['threads'][$profile] = $thread['id']; $this->saveConfig($config); return $thread['id']; } /** * Poser une question (méthode principale) */ public function ask($profile, $message, $assistantConfig = null) { // Configuration par défaut de l'assistant if ($assistantConfig === null) { //echo "Config Assistant par defaut"; $assistantConfig = [ 'name' => 'Assistant Domotique Jeedom', 'instructions' => 'Tu es un assistant domotique intelligent pour Jeedom. La maison contient : - Lumières dans le salon, cuisine, chambre, bureau, entrée - Volets dans chaque pièce - Capteurs de température et mouvement dans chaque pièce - Caméras de surveillance Tu dois aider à automatiser et contrôler ces équipements de manière intelligente. Réponds de façon concise et pratique.', 'model' => this.$model //'gpt-4-turbo' ]; }else{ //echo "Config Assistant personnalisée"; } $assistantId = $this->getOrCreateAssistant( $assistantConfig['name'], $assistantConfig['instructions'], (isset($assistantConfig['model'])? $assistantConfig['model'] : $this->model) ); //echo "ask assistantConfig Name :".$assistantConfig['name']."\n"; //echo "ask assistantConfig Name :".$assistantConfig['model']."\n"; //echo "ask assistantConfig Name :".$assistantConfig['instructions']."\n"; $threadId = $this->getOrCreateThread($profile); $this->addMessage($threadId, $message); $this->runAssistant($threadId, $assistantId); $messages = $this->getMessages($threadId, 1); //echo "ask messages:".$messages[0]['content'][0]); $response = $messages[0]['content'][0]['text']['value']; // Petit délai pour permettre la synchronisation du thread // Important si vous faites plusieurs appels successifs au même thread usleep(500000); // 0.5 seconde //echo "ask message :".$message."\n"; //echo "ask reponse :".$response."\n"; return $response; } /** * Réinitialiser la configuration (utile pour debug) */ public function resetConfig() { if (file_exists($this->configFile)) { unlink($this->configFile); return true; } return false; } } /* //Utilisation : require_once '/var/www/html/plugins/script/data/openAIAssistant.class.php'; // Initialiser l'assistant $ai = new OpenAIAssistant(OPENAI_API_KEY, CONFIG_FILE); // Exemple 2 : Depuis une variable de scénario // $profile = $scenario->getData('profile'); // $message = $scenario->getData('user_message'); // Exemple 3 : Détection de mouvement // $profile = 'Madame'; // $message = "Mouvement détecté. Dois-je allumer la lumière ?"; // Exemple 1 : Température du salon $profile = 'Monsieur'; $temperature = 22; // ou récupérez depuis une commande: cmd::byId(123)->execCmd() $message = "La température actuelle du salon est de {$temperature}°C"; $response = $ai->ask($profile, $message); $scenario->setLog("Question: ($profile) $message\n"); $scenario->setLog("Réponse: $response\n"); // Stocker dans une variable #$scenario->setData('ai_response', $response); // Vous pouvez aussi parser la réponse pour déclencher des actions // if (strpos($response, 'allumer') !== false) { // cmd::byId(456)->execCmd(); // Allumer lumière // } */ ?>