ChatGPT dans Jeedom?

Bonjour

Je remarque que l’IA, lors de la réinterprétation des messages, pour un même message d’origine qui revient parfois dans une journée, il sort la même réécriture, j’ai essayé ajouter une phrase dans le prompt, mais ca ne change rien, as tu ce comportement ?

$prompt .= « Soit inventif afin d’éviter la répétition si plusieurs messages sont envoyés dans la journée. »;

Et si on lui donne une liste de plaques d’immatriculation avec les noms des proprio elle serait donc capable de dire qui arrive!

1 « J'aime »

La plupart de llm du marché ne font pas de lien entre les prompt de sessions différentes. A ma connaissance, chatgpt le fait dans le cadre de « projets », une structure dans laquelle tu peux gérer plusieurs sessions, mais je pense que c’est dans la version pro

OUI, Non, pas ca !! :scream::cold_sweat::sob: RGPD

2 « J'aime »

Oui, en effet, il ne se souvient pas des précédentes réponses, donc c’est pas possible

RGPD ? j’ai fais ma déclaration CNIL

Je ne sais pas si ce n’est pas possible, peut-être que dans les API il y a cette notion de lien de session qui permet de lancer le prompt dans une même session, indiquer que le prompt doit être lancé dans un projet jeedom,… En tout cas c’est intéressant à creuser

1 « J'aime »

avec la version gratos, je doute mais je vais regarder

il faut faire attention au moteur gemini utilisé

Pour le contexte dans la version gratuite que ce soit en flash ou pro

Eh ben, ca a bien bougé ici depuis mon POC avec chatGPT.
Au passage, merci pour le passage a Mistral : j’ai quasi rien du changer a mon code grace a toi. :slight_smile:
Entre temps, j’utilise un peu Claude AI hors jeedom, et je viens de voir qu’on pouvais apparemment gérer le contexte d’une conversation par API.
Quelqu’un ici aurait deja testé l’API de Claude pour notre domotique?
Parce que l’integration du contexte serait quand meme un gros plus en conversation avec jeedom :
On lui passe une fois le json avec les capteurs de la maison, et ensuite on peut causer/corriger, valider…

Edit : j’ai surement dit une connerie : Claude ne garde pas le contexte sur plusieurs sessions http (a moins de le stocker et de lui renvoyer… bof.
Et pour les autres :

  • OpenAI GPT : Même principe, historique à renvoyer
  • Google Gemini : Propose un système de « chat sessions » avec ID
    Mais apparemment (a verifier), openAI propose une autre API « Assistant API d’OpenAI » qui aurait des « threads » persistés côté serveur.

Qqun a deja testé?

Bon ben j’avais un peu de temps et j’ai testé pour vous. Le système de threads d’openai marche très bien.
Cote jeedom, on a juste a récupérer l’id du thread, de le stocker (fichier Jason ou variable), et a le repasser lors des prochaines questions. Bon, du coup, on garde les limites de l’API d’openai, c’est a dire qu’il faut limiter au max la taille du Json avec l’état des commandes de jeedom, mais ça fonctionne bien. Je vous mettrais le code ici si vous voulez

2 « J'aime »

Bonjour

Merci de ce retour
Pourriez-vous nous donner des cas d’usage en exemple ?

Merci par avance

C’est simple : on va pouvoir discuter avec jeedom de façon plus simple.
Sans contexte, a chaque message, il faut tout répéter.
Avec du contexte, l’IA a de la mémoire. Plus besoin de tout répéter.
Et si l’IA pose une question, tu peux juste répondre.

Exemple :
Sans contexte :
Q: quelle est la température dans le salon?
R: 20 degrés
Q: quelle température fait-il dans le jardin?
R: 10 degrés. Veux-tu que j’augmente le chauffage?
Q:oui
R: je n’ai pas compris

Avec contexte :
Q: quelle est la température dans le salon?
R: 20 degrés
Q: et dans le jardin?
R: 10 degrés. Veux-tu que j’augmente le chauffage?
Q:oui
R: ok, je monte le chauffage a 22 degrés

2 « J'aime »

Tu pourrait nous faire un petit tuto de mise en place, ça pourrait être fou !!!
Thank’s

1 « J'aime »

Alors pour le tuto, désolé, je n’ai vraiment pas le temps. Par contre, je vous ai developpé une classe qui permet d’interroger l’API assistant d’openAI, avec une gestion des conversations par personne (au cas ou vous seriez plusieurs a la maison).

Moi j’ai branché ca sur mon scenario d’interraction sur telegram, pour une discussion plus simple, mais vous pouvez l’appeler comme bon vous semble.
openAIAssistant.class.php.txt (10,4 Ko)
Utilisation :
Renommer le fichier sans l’extension .txt (je l’ai mise pour pouvoir uploader le fichier sur le forum) et mettez le dans le dossier plugins/script/data de jeedom

Ensuite, ca s’utilise comme ca :

$openaiApiKey = $scenario->getData('OPENAI_API_KEY'); //TODO : Stokez votre Token openAI dans une variable OPENAI_API_KEY
$openaiModel = 'gpt-3.5-turbo'; //'gpt-4-turbo'
  	require_once '/var/www/html/plugins/script/data/openAIAssistant.class.php';

  	//$ai = new OpenAIAssistant($openaiApiKey,'/tmp/jeedom_openai_config.json');
       $ai = new OpenAIAssistant($openaiApiKey);
       
  	$assistantConfig = [
      'name' => 'Assistant Domotique Jeedom',
      'instructions' =>
        'Tu es un assistant domotique Jeedom. Je m\'appelle ' . $tagProfile . ".\n" .
        "Réponds toujours uniquement si tu es certain de la réponse et TOUJOURS sous la forme d'un JSON brut (et juste le JSON) contenant les champs suivants :\n" .
        " - question (reprise de la question d'origine simple SANS le json des valeurs des capteurs),\n" .
        " - response (réponse en langage naturel),\n" .
        " - piece (nom de la ou les pièces identifiées dans la question ET dans les infos domotiques, séparées par des virgules. Laisser vide si non identifiée),\n" .
        " - id (id de la commande, laisser vide si non trouvé),\n" .
        " - mode (action ou info).\n" .
        "Si la question est une demande d'action (de type allumer, éteindre, monter, descendre, ouvrir, fermer, ...), " .
        "il faut obligatoirement renseigner une variable 'mode' avec la valeur 'action', sinon, la variable contiendra 'info', si tu trouves la commande dans le JSON.\n" .
        "Quand je te demande d'allumer ou d'ouvrir un équipement, ne me réponds pas qu'il est déjà éteint ou fermé (et inversement).\n" .
        "Fais simplement ce que je te demande en renvoyant l'id de la commande dans le champ id, et la variable mode = 'action'.\n" 
        //."Voici les valeurs actuelles des capteurs de la domotique de la maison sur lesquelles baser ta réponse : ",// . $jeedom_json_result,
    ,'model' => $openaiModel
    ];
  
    $profile = $tagProfile; //$scenario->getData('profile');
  if(strtolower($prompt)=="reset" || strtolower($prompt)=="init"){
      if($debug_echo)  echo "REINITIALISATION DU CONTEXTE\n";
      $ai->resetConfig();
    }
  $prompt = "Quelle température fait-il dans le salon?";
   $message = $prompt."\n"."Voici les valeurs actuelles des capteurs de la domotique de la maison sur lesquelles baser ta réponse : ". $jeedom_json_result;

    $response = $ai->ask($profile, $message, $assistantConfig);

//Test de la persistance (attention a garder le meme profile)
$prompt = "Qu'est-ce que je viens de te demander?";
 $response = $ai->ask($profile, $message, $assistantConfig);

Bien sur, mes instructions sont relativement complexe, car mon scenario utilise la reponse en json pour ensuite allumer ou eteindre des trucs.
Voila, c’est juste un poc en mode quick and dirty, mais si d’autres veulent l’améliorer, c’est avec plaisir. :slight_smile:

2 « J'aime »

Mon scenario complet pour les plus courageux :

//Scenario d'interrogation d'une IA (provoqué par un autre scenario et necessitant les tags msg*, profile*, command, mode, piece) 
//$openaiApiKey = "xxx"; //Token API
$openaiApiKey = $scenario->getData('OPENAI_API_KEY'); //TODO : Stokez votre Token openAI dans une variable OPENAI_API_KEY
$openaiModel = 'gpt-3.5-turbo'; //'gpt-4-turbo'
$piecesInclus = array("Maison","Jardin","Piscine","Consos","Entrée","Salon","Salle à manger","Cuisine","Garage","12 niveau","Bibliothèque","Salle de bain","Chambre Parents","Bureau","Etage","Chambre Evan","Chambre Eliott"); //Liste des pieces dans lesquelles récupérer les infos et actions des equipements
//$piecesInclus = array("Cuisine"); //TEST
$equipementsExclus = array("Prise", "Volets", "Résumé", "Dodo", "Eteindre"); //Mots excluant certains équipements de la liste
$eqActionInclusCategories = array("light","opening","heating");	//"heating","security","energy","automatism","multimedia","default" //Catégories d'équipement pilotables par IA
$eqCmdExclus = array("Rafraichir", "binaire","Thumbnail"); //Terme excluant certaines Actions 
$debug_echo = true; //false;	//Afficher les messages de debug dans les logs
$debug_eq_echo = false; //false;	//Afficher la liste des equipements dans les logs

//if($debug_echo) {
//  ini_set('display_errors', 1);
//  ini_set('display_startup_errors', 1);
//  error_reporting(E_ALL);
//  $scenario->setLog("Affichage des erreurs");
//}else{
// 	$scenario->setLog("Pas d'affichage des erreurs"); 
//}

try {
  
  	/************************************************************************************************************************
     * Récupération des parametres du scenario et construction des infos de la maison a envoyer (etat des capteurs et actions)
     ************************************************************************************************************************/
  
    $tags = $scenario->getTags();
    //Tags : profile, msg, command
    $tagProfile = isset($tags['#profile#']) ? $tags['#profile#'] : 'Inconnu';	//Tag obligatoire permettant d'envoyer la notification de retour (via un scenario de notification)
  	//Le profile sert aussi a isoler les interractions dans un thread personnel. 
    $tagCommand = isset($tags['#command#']) ? $tags['#command#'] : '#[Aucun][Notification Telegram][Franck]#'; //TODO : Tag facultatif indiquant la commande de notification

    $pieces = [];
    $tagPieces = isset($tags['#piece#']) ? explode(',', $tags['#piece#']) : ''; //Tag optionnel permettant de filtrer sur une ou plusieurs pieces
    if(isset($tags['#piece#'])){
      foreach ($tagPieces as $piece) {
        if (in_array(strtolower(trim((string) $piece)), array_map('strtolower',$piecesInclus)) && !in_array(strtolower(trim((string) $piece)), array_map('strtolower',$pieces))) {
            $pieces[] = $piece;
        }
      }
    }else{
        $pieces = $piecesInclus;
    }
    $tagMode = isset($tags['#mode#']) ? $tags['#mode#'] : 'action'; //'info'; //Tag optionnel permettant de forcer l'envois des commandes info ou action
	
    if (isset($tags['#msg#'])){	//Tag obligatoire contenant la question
      $infoQuestion = trim((string) $tags['#msg#']);
      if($debug_echo) echo "msg :".$infoQuestion."\n";
    }else{
      if($debug_echo) echo "Aucune question.\n";
      $infoQuestion = "Bonjour";
      //$infoQuestion = "Y'a-t-il du courrier?";
      //$infoQuestion = "Toutes les fenêtres sont-elles fermées?";
     // $infoQuestion = "Quelle est la consommation d'eau aujourd'hui?";
      if($debug_echo) echo "msg par defaut :".$infoQuestion."\n";
    }

    $infoReponse = '';
    // Nettoyage de la valeur récupérée
    $prompt = trim((string) $infoQuestion);
    //$scenario->setLog("Question récupérée : ".$prompt);
    //if($debug_echo) echo "Question récupérée : ".$prompt";

    //*** Recupération des infos de Jeedom ***
    if($debug_echo) echo "Recupération des infos de Jeedom\n";
    $commands = [];
    $eqLogics = [];
    foreach ($pieces as $piece) {
      $object = jeeObject::byName($piece);
      //$piece = $object->getName();
      if (is_object($object) && $object->getIsVisible() == 1) {
        //$eqLogics = $eqLogics + $object->getEqLogic(true);
          $eqLogics2 = array_merge($eqLogics, $object->getEqLogic(true));
          $eqLogics = $eqLogics2;
      }
    }

    $piecePrev = "";
    foreach ($eqLogics as $eqLogic) {
      // Ajout des informations de l'équipement dans le tableau
      if ($eqLogic->getIsEnable() == 1 && $eqLogic->getIsVisible()==1) {
        $piece = $eqLogic->getObject()->getName();
        if ($piece != $piecePrev){
          $piecePrev = $piece; 
        }
        $eqName = $eqLogic->getName();

        $found = false;
        foreach ($equipementsExclus as $element) {
          if (strpos($eqName, $element) !== false) {
            $found = true;
            break;
          }
        }

        if(!$found){
          if($debug_eq_echo) echo "| -".$eqName."\n";

          $isAuthorizedCatAction = false;      
          foreach ($eqActionInclusCategories as $eqActionInclusCategory){

            if($eqLogic->getCategory($eqActionInclusCategory)==1) {
              if($debug_eq_echo) echo "|  Cat ".$eqActionInclusCategory." : OK (".$eqLogic->getCategory($eqActionInclusCategory).")\n";
              $isAuthorizedCatAction = true;
              break;
            }else{
                if($debug_eq_echo) echo "|  Cat ".$eqActionInclusCategory." : KO! (".$eqLogic->getCategory($eqActionInclusCategory).")\n";
            }
          }

          $cmds = $eqLogic->getCmd();
          $eqCmds = [];
          foreach ($cmds as $cmd) {
            //if($debug_eq_echo) echo "  - ".$cmd->getType()." ".$cmd->getHumanName()."\n";
            $cmdName = $cmd->getName();

            $foundCmd = false;
            foreach ($eqCmdExclus as $element) {
              if (strpos($cmdName, $element) !== false) {
                $foundCmd = true;
                break;
              }
            }

            if(!$foundCmd){
              if (  ($cmd->getIsVisible()==1 || $cmdName=="Etat")) { //$cmd->getType() === 'info' &&
                //if($debug_eq_echo) echo "|  -".$cmd->getType()." ".$cmd->getHumanName()."\n";
                //$cmdName = $cmd->getHumanName();
                //$cmdName = str_replace("][", " ", $cmdName);
                //$cmdName = str_replace(']', '', $cmdName);
                //$cmdName = str_replace('[', '', $cmdName);
                //$cmdName = trim($cmdName);
                $cmdType = $cmd->getType();
                if($tagMode==='action' && $cmdType==='action'){

                  if($isAuthorizedCatAction){
                    if(((strpos($eqName,"Lumière")!==false)||(strpos($eqName,"lampe")!==false)||(strpos($eqName,"led")!==false)) ) {
                      $cmdName = str_replace(["On","Off"], ["Allumer","Eteindre"], $cmdName);
                    }
                    if($debug_eq_echo) echo "|  -".$cmd->getType()." ".$cmd->getHumanName()." ".$eqName." ".$cmdName."\n";

                    $eqCmds[$cmdName] = [
                      'id' => $cmd->getId(),
                      //'nom' => $cmdName,
                      //'type' => $cmdType,
                      //'subType' => $cmd->getSubType(),
                      //'value' => $cmdValue,
                      //'unit' => $cmd->getUnite(),
                      //'value date' => $cmd->getValueDate()
                    ];
                  }

                }

                if($cmdType==='info'){
                  $cmdValue = "";
                  $cmdValue = $cmd->execCmd();
                  if($debug_eq_echo) echo "|  -".$cmd->getType()." ".$cmd->getHumanName()." : ".$cmdValue."";

                  if ($cmdValue !== "") {
                    if(!(strpos($eqName,"Porte")===false) && $cmdName=="Etat") $cmdValue = str_replace(array(0,1), array("Ouverte","Fermée"), $cmdValue);
                    if(!(strpos($eqName,"Volet")===false) && $cmdName=="Etat") $cmdValue = str_replace(array(0,1), array("Ouvert","Fermé"), $cmdValue);
                    if(!(strpos($eqName,"Fenêtre")===false) && $cmdName=="Etat") $cmdValue = str_replace(array(0,1), array("Fermée","Ouverte"), $cmdValue);
                    if((!(strpos($eqName,"Lumière")===false)||!(strpos($eqName,"lampe")===false)||!(strpos($eqName,"led")===false)) && $cmdName=="Etat") {
                      $cmdValue = str_replace(array(255,0,1), array("Allumée","Eteinte","Allumée"), $cmdValue);//0=éteinte, 1=allumée
                    }
                    if($cmd->getUnite()!=="") { $cmdValue = $cmdValue.$cmd->getUnite(); }
                    if($debug_eq_echo) echo "  (".$cmdValue." :OK) \n";
                    $eqCmds[$cmdName] = $cmdValue;
                    //HS : trop volumineux :(
                    /*$eqCmds[$cmdName] = [
                      'id' => $cmd->getId(),
                      //'nom' => $cmdName,
                      //'type' => $cmdType,
                      //'subType' => $cmd->getSubType(),
                      'value' => $cmdValue,
                      //'unit' => $cmd->getUnite(),
                      //'value date' => $cmd->getValueDate()
                    ];*/

                  }else{
                    if($debug_eq_echo) echo "  (".$cmdName." :vide) \n"; 
                  }
                }

              }

            }
          }
          if(!empty($eqCmds)){
            //echo "eqCmds : \n".json_encode($eqCmds, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)."\n\n";
            $commands[$piece][$eqName] = $eqCmds;
            //$commands[$piece][$eqName][] = ['catégorie' => $eqCategory];
          }
        }
      }
    }

    $jeedom_json_result = json_encode($commands, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);	
    if($debug_eq_echo) echo "equipements : \n$jeedom_json_result\n\n";
    //echo "******* length : ".strlen($jeedom_json_result).".\n";

  
     /*****************************************************************************************************
     * Interrogation de l'assistant IA
     ******************************************************************************************************/
    if($debug_echo) echo "Initialisation de l'assistant IA\n";
  	require_once '/var/www/html/plugins/script/data/openAIAssistant.class.php';
    if($debug_echo) echo "Initialisation de l'assistant IA terminée\n";
  	
  	//$ai = new OpenAIAssistant($openaiApiKey,'/tmp/jeedom_openai_config.json');
    $ai = new OpenAIAssistant($openaiApiKey);
       
  	$assistantConfig = [
      'name' => 'Assistant Domotique Jeedom',
      'instructions' =>
        'Tu es un assistant domotique Jeedom. Je m\'appelle ' . $tagProfile . ".\n" .
        "Réponds toujours uniquement si tu es certain de la réponse et TOUJOURS sous la forme d'un JSON brut (et juste le JSON) contenant les champs suivants :\n" .
        " - question (reprise de la question d'origine simple SANS le json des valeurs des capteurs),\n" .
        " - response (réponse en langage naturel),\n" .
        " - piece (nom de la ou les pièces identifiées dans la question ET dans les infos domotiques, séparées par des virgules. Laisser vide si non identifiée),\n" .
        " - id (id de la commande, laisser vide si non trouvé),\n" .
        " - mode (action ou info).\n" .
        "Si la question est une demande d'action (de type allumer, éteindre, monter, descendre, ouvrir, fermer, ...), " .
        "il faut obligatoirement renseigner une variable 'mode' avec la valeur 'action', sinon, la variable contiendra 'info', si tu trouves la commande dans le JSON.\n" .
        "Quand je te demande d'allumer ou d'ouvrir un équipement, ne me réponds pas qu'il est déjà éteint ou fermé (et inversement).\n" .
        "Fais simplement ce que je te demande en renvoyant l'id de la commande dans le champ id, et la variable mode = 'action'.\n" 
        //."Voici les valeurs actuelles des capteurs de la domotique de la maison sur lesquelles baser ta réponse : ",// . $jeedom_json_result,
    ,'model' => $openaiModel
    ];
  
    $profile = $tagProfile; //$scenario->getData('room');
  	if(strtolower($prompt)=="reset" || strtolower($prompt)=="init"){
      if($debug_echo)  echo "REINITIALISATION DU CONTEXTE\n";
      $ai->resetConfig();
    }
  
    $message = $prompt."\n"."Voici les valeurs actuelles des capteurs de la domotique de la maison sur lesquelles baser ta réponse : ". $jeedom_json_result;

    if($debug_echo) echo "Interrogation de l'assistant IA\n";
    $response = $ai->ask($profile, $message, $assistantConfig);
    //if($debug_echo)  echo "Question scenario: (".$profile.") ".$message."\n";
    if($debug_echo)  echo "Réponse BRUT 1: ".$response."\n";
    
	/****************************************************************************************************************
    * Traitement de la réponse
    *****************************************************************************************************************/
    
    $responseData = json_decode($response, true);
    if($debug_echo)  echo "******** Traitement de la réponse ************\n";
    if($debug_echo)  echo "Réponse BRUT 2 : " . print_r($responseData, true)."\n";

    if (isset($responseData['choices'][0]['message']['content'])) {
      $aiResponse = trim((string) $responseData['choices'][0]['message']['content']);
    } else {
      $aiResponse = $responseData; //trim((string) $responseData);
    }

    if (isset($aiResponse)) {

      if(!is_array($aiResponse)){
          $aiResponse = preg_replace('/^```json\s*|\s*```$/m', '', $aiResponse);
          //if($debug_echo)  echo "DEBUG2 ".$aiResponse."\n";
          $aiResponseJson = json_decode($aiResponse, true);
          //if($debug_echo)  echo "DEBUG3 ".$aiResponseJson."\n";
      }else{
       	$aiResponseJson =  $aiResponse;
      }
            
      if (isset($aiResponseJson['response'])) {
        if($debug_echo) echo "JSON : ".$aiResponse."\n";
        if($debug_echo) echo "Réponse JSON : ".$aiResponseJson['response']."\n";
        $infoReponse = trim((string) $aiResponseJson['response']);

        if (isset($aiResponseJson['mode']) && $aiResponseJson['mode']=='action') {
          if($debug_echo) echo "Réponse JSON mode '".$aiResponseJson['mode']."'\n";
          if (isset($aiResponseJson['id']) ) {
            if($debug_echo) echo "Réponse JSON id '".$aiResponseJson['id']."'\n";
            //TODO : Si action ou bloucle, rappel du scenario avec des tag action, etc...
            $cmdId = $aiResponseJson['id'];
            $cmdAction=cmd::byId($cmdId);
            if (is_object($cmdAction)) {
              //$eqAction = $cmdAction->getEqLogic();
              if($cmdAction->getType()=='action'){
                $cmdActionName = $cmdAction->getHumanName();
                if($debug_echo) echo "ACTION ==> ".$cmdAction->getType()." ".$cmdActionName."\n";
                $cmdAction->execCmd(); // Execute l'action
                $infoReponse = $infoReponse." (".$cmdActionName.")";
              }
              //cmd::byId($idMsg)->event($myMsg);
            }
          }else{
            $infoReponse = $infoReponse." (Commande non trouvée)";
          }
        }

      } else {
        if($debug_echo) echo "Réponse TEXT : ".$aiResponse."\n";
        $infoReponse = $aiResponse;
      }

    } else {
        $infoReponse = "Erreur : Aucune réponse valide reçue à la question : ".$infoQuestion.".";
        //exit;
    }

  	/****************************************************************************************************************
    * Envoi de la réponse
    *****************************************************************************************************************/
    
    if($debug_echo) echo "****************************\n";
    echo "Question de ".$tagProfile." : ".$infoQuestion."\n";
    echo "Réponse de l'ia : ".print_r($infoReponse, true)."\n";
    // Envoi de la réponse à l'équipement Jeedom (ID )
    //TODO : si erreur de l'appel API, alors vidage du contexte

    if($debug_echo) echo "Envoi à ".$tagProfile."\n";
    $scenario = scenario::byId(387); //TODO : personnaliser le numero du scenario d'envoi ou de tout autre moyen de retour ici
    $tags = $scenario->getTags();
    #Ajouter des tags

    $tags['#profile#'] = ($tagProfile!='Inconnu' && $tagProfile!='') ? $tagProfile : 'Franck'; //TODO : destinataire par defaut du message retour
    $tags['#msg#'] = $infoReponse;
    $tags['#command#'] = $tagCommand;
    $scenario->setTags($tags);
    $scenario->launch(); 
    if($debug_echo) echo "*************************************************************\n";
    
  	/****************************************************************************************************************
    * 
    *****************************************************************************************************************/
    
} catch (Exception $e) {
    $errorMsg = "Erreur OpenAI: " . $e->getMessage();
    
    if (isset($scenario)) {
        $scenario->setLog($errorMsg);
    }
    
    echo $errorMsg . "\n";
    // Vous pouvez aussi envoyer une notification, etc.
}

// ============================================
// COMMANDES UTILES (décommentez si besoin)
// ============================================

// Réinitialiser la configuration (supprime assistant et threads)
// $ai->resetConfig();

// Obtenir un nouveau thread pour une pièce spécifique
// $threadId = $ai->getOrCreateThread('cuisine');
2 « J'aime »

Petites améliorations du prompt, et du model : gpt-4o-mini est moins cher, plus rapide et plus précis que ce benet de gpt-3.5-turbo
EDIT : J’ai (beaucoup) amélioré mon code et packagé ca dans un github. J’ai fait un post dédié pour pas polluer celui-là : Jeedom Assistant AI (un peu d'IA dans Jeedom)

:slight_smile:

J’encourage tous ceux qui ont joué avec l’API de openai, gemini ou claude pour discuter avec Jeedom, d’aller voir cette suggestion et de vous documenter sur l’avenir de l’IA dans nos systèmes, à savoir, le protocol MCP :blush:

1 « J'aime »