Initial commit of current engine library state.
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
composer.lock
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
vendor/
|
||||||
32
CamsAIEngine.msbuildproj
Executable file
32
CamsAIEngine.msbuildproj
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
<Project Sdk="Peachpie.NET.Sdk/1.2.0-r15367">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>library</OutputType>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
<ComposerAutoload>true</ComposerAutoload>
|
||||||
|
<PackageId>CamsAI</PackageId>
|
||||||
|
<Authors>Toxus</Authors>
|
||||||
|
<Product>CamsAI</Product>
|
||||||
|
<AssemblyName>CamsAI</AssemblyName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="**/*.php" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="**/test/**/*.php" />
|
||||||
|
<Compile Remove="**/tests/**/*.php" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="vendor\lfischer\open-weather-map-api\src\RequestAdapter\Guzzle.php" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="HADotNet.Core" Version="1.6.0" />
|
||||||
|
<PackageReference Include="Peachpie.Library.Scripting" Version="1.2.0-r15367" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\AIML\Aiml\Aiml.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Update="Peachpie.App" Version="1.2.0-r15367" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
19
composer.json
Executable file
19
composer.json
Executable file
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
52
src/CamsAI/CamSensory.class.php
Executable file
52
src/CamsAI/CamSensory.class.php
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// TODO: Look at .NET based Home Assistant Libraries
|
||||||
|
|
||||||
|
namespace CamsAI;
|
||||||
|
|
||||||
|
class SensoryEngine
|
||||||
|
{
|
||||||
|
protected $sensors;
|
||||||
|
protected $currentAction;
|
||||||
|
private $linfo;
|
||||||
|
private $linfo_parser;
|
||||||
|
|
||||||
|
function __construct() {
|
||||||
|
// Get System Information
|
||||||
|
$this->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']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
169
src/CamsAI/Engine.class.php
Executable file
169
src/CamsAI/Engine.class.php
Executable file
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
use Aiml;
|
||||||
|
use System\Reflection\Assembly;
|
||||||
|
use lfischer\OpenWeatherMap\API;
|
||||||
|
include_once("src\CamsAI\SraixServices\Weather.SraiX.php");
|
||||||
|
include_once("src\CamsAI\SraixServices\HomeAssistant.SraiX.php");
|
||||||
|
include_once("vendor/autoload.php");
|
||||||
|
namespace CamsAI;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C.A.M.S AI Engine DLL Class
|
||||||
|
*/
|
||||||
|
class Engine
|
||||||
|
{
|
||||||
|
public $bot;
|
||||||
|
public $user;
|
||||||
|
private $currentPlatform;
|
||||||
|
|
||||||
|
function __construct($pBotConfig, $Username = null) {
|
||||||
|
// System.Reflection.Assembly.GetCallingAssembly().GetName().Version
|
||||||
|
$Version = \System\Reflection\Assembly::GetCallingAssembly()->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>(.*?)<\/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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
src/CamsAI/SraiXServices/HomeAssistant.SraiX.php
Executable file
18
src/CamsAI/SraiXServices/HomeAssistant.SraiX.php
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
use Aiml;
|
||||||
|
namespace CamsAI\SraixServices;
|
||||||
|
|
||||||
|
class HomeAssistant implements \Aiml\ISraixService
|
||||||
|
{
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function Process(String $text, $attributes, \Aiml\RequestProcess $RequestProcess)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
49
src/CamsAI/SraiXServices/PolkitInterop.SraiX.php
Executable file
49
src/CamsAI/SraiXServices/PolkitInterop.SraiX.php
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
use \Aiml;
|
||||||
|
|
||||||
|
namespace CamsAI\SraixServices;
|
||||||
|
class PolkitInterop implements \Aiml\ISraixService
|
||||||
|
{
|
||||||
|
|
||||||
|
private $authority;
|
||||||
|
private $subject;
|
||||||
|
private $identity;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$system_name = php_uname('s');
|
||||||
|
if($system_name == "Linux")
|
||||||
|
{
|
||||||
|
$this->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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
src/CamsAI/SraiXServices/Weather.SraiX.php
Executable file
63
src/CamsAI/SraiXServices/Weather.SraiX.php
Executable file
@@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use \Aiml;
|
||||||
|
use \lfischer\openWeatherMap\API;
|
||||||
|
use lfischer\openWeatherMap\RequestAdapter\Curl;
|
||||||
|
|
||||||
|
|
||||||
|
namespace CamsAI\SraixServices;
|
||||||
|
|
||||||
|
class Weather implements \Aiml\ISraixService
|
||||||
|
{
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function Process(String $text, $attributes, \Aiml\RequestProcess $RequestProcess)
|
||||||
|
{
|
||||||
|
|
||||||
|
$Location = $RequestProcess->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
todo.txt
Normal file
10
todo.txt
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user