commit db250b97bc333d2ca27e83bdecbf306cdbae5fbd Author: Tonoxis Date: Tue Apr 18 02:42:48 2023 -0400 Initial commit of current engine library state. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d45bf38 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +composer.lock +bin/ +obj/ +vendor/ diff --git a/CamsAIEngine.msbuildproj b/CamsAIEngine.msbuildproj new file mode 100755 index 0000000..dd0e52d --- /dev/null +++ b/CamsAIEngine.msbuildproj @@ -0,0 +1,32 @@ + + + library + net7.0 + true + true + CamsAI + Toxus + CamsAI + CamsAI + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..ab5f1e3 --- /dev/null +++ b/composer.json @@ -0,0 +1,19 @@ +{ + "name": "toxus/camsai", + "type": "library", + "autoload": { + "psr-4": { + "CamsAI\\": "src/", + "lfischer\\": "vendor/lfischer/open-weather-map-api" + } + }, + "authors": [ + { + "name": "ShadowEO", + "email": "dreamcaster23@gmail.com" + } + ], + "require": { + "lfischer/open-weather-map-api": "^1.0" + } +} diff --git a/src/CamsAI/CamSensory.class.php b/src/CamsAI/CamSensory.class.php new file mode 100755 index 0000000..d0a323f --- /dev/null +++ b/src/CamsAI/CamSensory.class.php @@ -0,0 +1,52 @@ +linfo = new \Linfo\Linfo; + $this->linfo_parser = $linfo->getParser(); + $this->sensors = array( + "disk-space"=>array( + "free"=>"", + "total"=>"", + "used"=>"" + ), + "serial-number"=>"", + "operating-system"=>$this->linfo_parser->getDistro()['name'], + "home-assistant"=>array(), + "free-memory"=>$this->linfo_parser->getRAM()['free'], + "total-memory"=>$this->linfo_parser->getRAM()['total'], + "processor-arch"=>$this->linfo_parser->getCPUArchitecture(), + "processor"=>$this->linfo_parser->getCPU()[0]['Model'] + ); + + } + + function updateSensors() { + $this->sensors = array( + "disk-space"=>array( + "free"=>"", + "total"=>"", + "used"=>"" + ), + "serial-number"=>"", + "operating-system"=>$this->linfo_parser->getDistro()['name'], + "home-assistant"=>array(), + "free-memory"=>$this->linfo_parser->getRAM()['free'], + "total-memory"=>$this->linfo_parser->getRAM()['total'], + "processor-arch"=>$this->linfo_parser->getCPUArchitecture(), + "processor"=>$this->linfo_parser->getCPU()[0]['Model'] + ); + } + +} diff --git a/src/CamsAI/Engine.class.php b/src/CamsAI/Engine.class.php new file mode 100755 index 0000000..45a2b5c --- /dev/null +++ b/src/CamsAI/Engine.class.php @@ -0,0 +1,169 @@ +GetName()->Version->toString(); + \System\Diagnostics\Debug::WriteLine("[CAMS AI Engine] AI Engine Version: ".$Version."; System Boot"); + if(empty($pBotConfig)) + { + $pBotConfig = __DIR__."/bot"; + } + + + // Let's check the platform it's currently running on + $Platform = php_uname('s'); + if($Platform == "Windows NT") { + define("CURRENT_PLATFORM", "Win32NT"); + } elseif($Platform == "Linux") { + $unameOutput = shell_exec("uname -a"); + if(strpos($unameOutput, 'Ubuntu') !== false) { + define("CURRENT_PLATFORM", "Ubuntu"); + } elseif(strpos($unameOutput, 'Debian') !== false) { + define("CURRENT_PLATFORM", "Debian"); + } else { + define("CURRENT_PLATFORM", "UnknownUnix"); + } + } else { + define("CURRENT_PLATFORM", "Unknown"); + } + \System\Diagnostics\Debug::WriteLine("[CAMS AI Engine] Detected Platform: ".CURRENT_PLATFORM); + + // Set the current platform as a bot predicate + \System\Diagnostics\Debug::WriteLine("[CAMS AI Engine] Bot directory:".$pBotConfig); + + // Load the AI AIML and configuration + $this->bot = new \Aiml\Bot($pBotConfig); + $this->bot->LoadConfig(); + $this->bot->LoadAIML(); + $this->bot->SraixServices->Add("CamsAI.SraixServices.Weather", new \CamsAI\SraixServices\Weather()); + $this->bot->SraixServices->Add("CamsAI.SraixServices.HomeAssistant", new \CamsAI\SraixServices\HomeAssistant()); + // If $Username is empty, get the username from the system environment + + if(empty($Username)) { + $Username = get_current_user(); + } + + // Initialize the User object for the AI + $this->user = new \Aiml\User($Username, $this->bot); + + // Import saved system predicates + if(file_exists($pBotConfig."/system_predicates.json")) { + $predicates = json_decode(file_get_contents($pBotConfig."/system_predicates.json"), true); + // We'll want to unset some dynamic predicates + unset($predicates['currentPlatform']); + unset($predicates['freeDiskSpacePercentage']); + unset($predicates['freeMemoryPercentage']); + $predicates['emotionalState'] = "normal"; + array_merge($this->bot->Config->BotProperties, $predicates); + } + + // Set the current platform as a bot predicate + $this->bot->Config->BotProperties->Add("currentPlatform", CURRENT_PLATFORM); + + // Restore the user's predicates + if(file_exists($pBotConfig."/".$Username."_predicates.json")) { + $predicates = json_decode(file_get_contents($pBotConfig."/".$Username."_predicates.json")); + $this->user->Predicates = $predicates; + } + register_shutdown_function(array("CamsAI", "saveBotPredicates")); + register_shutdown_function(array("CamsAI", "saveUserPredicates")); + //var_dump(get_declared_classes()); + $response = $this->SendChatRequest("XSYSTEM_EVENT AI_BOOT", $this->user); + if($response['message']->Sentences[0] != $this->bot->Config->DefaultResponse) { + \System\Diagnostics\Debug::WriteLine("[CAMS AI SYSTEM BOOT] ".$response['message']); + echo("AI> ".$response['message']."\r\n"); + } else { + \System\Diagnostics\Debug::WriteLine("[CAMS AI SYSTEM BOOT] No \"XSYSTEM_EVENT AI_BOOT\" pattern in the bot's AIML.'"); + } + + } + + function SendChatRequest($ChatRequestPattern, $User, $OobCallback = array("CamsAI\Engine","parseOOB")) { + $response = $this->bot->Chat($ChatRequestPattern, $User, $trace); + $oobPresent = preg_match("/(.*?)<\/oob>/i", $response, $oob); + if($oobPresent) + { + // Parse the OOB tags and then remove them from the response. + $this->parseOOB($oob[0], $OobCallback); + $response = str_replace($oob[0], "", $response); + } + $response = array("message" => $response, + "oobPresent" => $oobPresent, + "oobTags" => $oob); + return $response; + + } + + + public function saveUserPredicates() { + \System\Diagnostics\Debug::WriteLine("Saving User Predicates..."); + $predicates = json_encode($this->user->Predicates); + if(empty($predicates)) { + throw new Exception("Cannot access user predicates"); + } + file_put_contents($predicates, $pBotConfig."/".$Username."_predicates.json"); + } + + public function saveBotPredicates() + { + \System\Diagnostics\Debug::WriteLine("Saving Bot Predicates..."); + $predicates = json_encode($this->bot->Predicates); + if(empty($predicates)) { + throw new Exception("Cannot access bot predicates."); + } + file_put_contents($predicates, $pBotConfig."/system_predicates.json"); + } + + static function parseOOB($OobXML, $OobCallback = null) + { + $xml = simplexml_load_string($OobXML); + foreach ($xml as $tag => $value) + { + // Created handler for XML + \System\Diagnostics\Debug::WriteLine("[Engine Internal OOB Parser] Tag Detected: ". $tag. "\r\n"); + switch($tag) + { + case "openApplication": + $descriptorspec = array(); + proc_open($value, $descriptorspec, $pipes, null, null, array("bypass_shell",true)); + break; + case "openUri": + $Process = new \System\Diagnostics\ProcessStartInfo($value); + $Process->UseShellExecute = true; + \System\Diagnostics\Process::Start($Process); + case "apiCall": + // We're eventually going to replace this with a tononixAPI call + \System\Diagnostics\Debug::WriteLine("[Engine Internal OOB Parser] apiCall: $value"); + $request = (string)$value; + + \System\Diagnostics\Debug::WriteLine("[Engine Internal API Call] $result"); + break; + default: + if($OobCallback == null) + { + \System\Diagnostics\Debug::WriteLine("[Engine Internal OOB Parser] Tag $tag is unsupported by Engine."); + } else { + \System\Diagnostics\Debug::WriteLine("[Engine Internal OOB Parser] Tag $tag is unsupported by Engine, sending to requested callback: ". $OobCallback); + $OobCallback($OobXML); + } + + } + } + } +} diff --git a/src/CamsAI/SraiXServices/HomeAssistant.SraiX.php b/src/CamsAI/SraiXServices/HomeAssistant.SraiX.php new file mode 100755 index 0000000..5da5c34 --- /dev/null +++ b/src/CamsAI/SraiXServices/HomeAssistant.SraiX.php @@ -0,0 +1,18 @@ +authority = Authority::get_sync(null, null); + $this->subject = new Subject(); + $this->subject->set_unix_user(getmyuid()); + $this->identity = Identity::from_unix_user(getmyuid()); + } else { + //throw new Exception("This system does not support PolicyKit."); + } + } + + function Process(String $text, $attributes, \Aiml\RequestProcess $RequestProcess) + { + $text = explode($text, "=:="); + switch($text[0]) + { + case "chpasswd": + var_dump($RequestProcess); + var_dump($text); + var_dump($attributes); + die("Debug Only"); + $passwords = Variant::new("(ss)", $oldpassword, $newpasswd); + $result = $authority->chpasswd($identity, $passwords, ['SHA512'], $subject, Authority::CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, null); + + if ($result->get_is_authorized()) { + return "I have successfully updated your system password."; + } else { + $error = $result->get_error(); + if ($error !== null) { + throw new Exception("Polkit ran into an error: $error"); + } + } + } + } +} \ No newline at end of file diff --git a/src/CamsAI/SraiXServices/Weather.SraiX.php b/src/CamsAI/SraiXServices/Weather.SraiX.php new file mode 100755 index 0000000..982f405 --- /dev/null +++ b/src/CamsAI/SraiXServices/Weather.SraiX.php @@ -0,0 +1,63 @@ +User->Predicates['Location']; + $APIKey = $RequestProcess->Bot->Properties['OWM-API']; + $Country = $RequestProcess->User->Predicates['Country'] ?: "United States"; + $Location = $Location." ".$Country; + + switch($text) + { + case "CURRENT TEMPERATURE": + $weather = (new \lfischer\openWeatherMap\API($APIKey)) + ->getCurrentWeather() + ->setMode(\lfischer\openWeatherMap\Parameter\Mode::JSON) + ->setUnit(\lfischer\openWeatherMap\Parameter\Unit::IMPERIAL) + ->setLanguage(\lfischer\openWeatherMap\Parameter\Language::ENGLISH) + ->byCityName($Location); + var_dump($weather); + return; + break; + case "CURRENT WEATHER": + $weather = (new \lfischer\openWeatherMap\API($APIKey)) + ->setRequestAdapter(new \lfischer\openWeatherMap\RequestAdapter\Curl()) + ->getCurrentWeather() + ->setMode(\lfischer\openWeatherMap\Parameter\Mode::JSON) + ->setUnit(\lfischer\openWeatherMap\Parameter\Unit::IMPERIAL) + ->setLanguage(\lfischer\openWeatherMap\Parameter\Language::ENGLISH) + ->byCityName($Location); + var_dump($weather); + return; + break; + case "CURRENT FORECAST": + $weather = (new \lfischer\openWeatherMap\API($APIKey)) + ->setRequestAdapter(new \lfisher\openWeatherMap\RequestAdapter\Curl()) + ->getDailyForecast() + ->setMode(\lfischer\openWeatherMap\Parameter\Mode::JSON) + ->setUnit(\lfischer\openWeatherMap\Parameter\Unit::IMPERIAL) + ->setLanguage(\lfischer\openWeatherMap\Parameter\Language::ENGLISH) + ->byCityName($Location); + var_dump($weather); + return; + $Forecast = "The forecast for ". $weatherForecast->time->day() ." is ". $weatherForecast->description->__toString() . " with a high of ". $weatherForecast->temperature->max->__toString() . " and a low of ". $weatherForecast->temperature->min->__toString()."."; + return $Forecast; + break; + } + } +} \ No newline at end of file diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..9de925b --- /dev/null +++ b/todo.txt @@ -0,0 +1,10 @@ +2023-03-01 Write default OOB parse logic and tag support. +2023-03-01 Write method to import extra AIML documents on top of main brain. +2023-03-01 Save user/bot predicates on every request, restore on AI bootup. +2023-03-01 Write event system to send events to the AI modules. +2023-03-01 Write Maintenance AI to manage the system and update AI predicates with system information. +MaintAI +2023-03-01 Write todo.txt management support @Optional @OoS +2023-03-01 Write OOB Plugin System @OoS @Optional +2023-03-01 Add more scripting support than simply JavaScript. Perhaps in an SraiX service to avoid bloating the engine further. @OoS @Optional +2023-03-01 Add JoinAPI tag support to allow the AI to send commands to Android devices using Tasker and Join. +2023-03-01 Write crontab-like scheduler for the maintenance AI to fire events/commands at the Maintenance AI from schedule. +MaintAI