BxDolAI.php 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <?php defined('BX_DOL') or die('hack attempt');
  2. /**
  3. * Copyright (c) UNA, Inc - https://una.io
  4. * MIT License - https://opensource.org/licenses/MIT
  5. *
  6. * @defgroup UnaCore UNA Core
  7. * @{
  8. */
  9. define('BX_DOL_AI_AUTOMATOR_EVENT', 'event');
  10. define('BX_DOL_AI_AUTOMATOR_SCHEDULER', 'scheduler');
  11. define('BX_DOL_AI_AUTOMATOR_WEBHOOK', 'webhook');
  12. define('BX_DOL_AI_AUTOMATOR_STATUS_AUTO', 'auto');
  13. define('BX_DOL_AI_AUTOMATOR_STATUS_MANUAL', 'manual');
  14. define('BX_DOL_AI_AUTOMATOR_STATUS_READY', 'ready');
  15. class BxDolAI extends BxDolFactory implements iBxDolSingleton
  16. {
  17. protected $_oDb;
  18. protected $_sPathInst;
  19. protected $_iProfileId;
  20. protected $_aExcludeAlertUnits;
  21. protected function __construct()
  22. {
  23. if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
  24. trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
  25. parent::__construct();
  26. $this->_oDb = new BxDolAIQuery();
  27. $this->_sPathInst = BX_DIRECTORY_PATH_ROOT . 'ai/instructions/';
  28. $this->_iProfileId = (int)getParam('sys_profile_bot');
  29. $this->_aExcludeAlertUnits = [
  30. 'system', 'module_template_method_call'
  31. ];
  32. }
  33. /**
  34. * Prevent cloning the instance
  35. */
  36. public function __clone()
  37. {
  38. if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
  39. trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
  40. }
  41. /**
  42. * Get singleton instance of the class
  43. */
  44. public static function getInstance()
  45. {
  46. if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
  47. $GLOBALS['bxDolClasses'][__CLASS__] = new BxDolAI();
  48. return $GLOBALS['bxDolClasses'][__CLASS__];
  49. }
  50. public function getProfileId()
  51. {
  52. return $this->_iProfileId;
  53. }
  54. public function getAutomatorInstructions($sType, $bIncludeCommon = false)
  55. {
  56. $sResult = file_get_contents($this->_sPathInst . $sType . '.html');
  57. if($bIncludeCommon)
  58. $sResult .= file_get_contents($this->_sPathInst. 'common.html');
  59. return $sResult;
  60. }
  61. public function getModel($iId)
  62. {
  63. $aModel = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $iId]);
  64. if(!empty($aModel['params']))
  65. $aModel['params'] = json_decode($aModel['params'], true);
  66. return $aModel;
  67. }
  68. public function getAutomator($iId, $bFullInfo = false)
  69. {
  70. $aAutomator = $this->_oDb->getAutomatorsBy(['sample' => 'id' . ($bFullInfo ? '_full' : ''), 'id' => $iId]);
  71. if(!empty($aAutomator['params']))
  72. $aAutomator['params'] = json_decode($aAutomator['params'], true);
  73. if($bFullInfo && !empty($aAutomator['model_params']))
  74. $aAutomator['model_params'] = json_decode($aAutomator['model_params'], true);
  75. return $aAutomator;
  76. }
  77. public function getAutomatorsEvent($sUnit, $sAction)
  78. {
  79. if(in_array($sUnit, $this->_aExcludeAlertUnits))
  80. return [];
  81. return $this->_oDb->getAutomatorsBy([
  82. 'sample' => 'events',
  83. 'alert_unit' => $sUnit,
  84. 'alert_action' => $sAction,
  85. 'active' => true
  86. ]);
  87. }
  88. public function getAutomatorsScheduler()
  89. {
  90. $aAutomators = $this->_oDb->getAutomatorsBy(['sample' => 'schedulers', 'active' => true]);
  91. foreach($aAutomators as &$aAutomator)
  92. if(!empty($aAutomator['params']))
  93. $aAutomator['params'] = json_decode($aAutomator['params'], true);
  94. return $aAutomators;
  95. }
  96. public function chat($sEndpoint, $sModel, $sApiKey, $aParams, $aMessages)
  97. {
  98. $aData = [
  99. 'model' => $sModel,
  100. 'messages' => $aMessages
  101. ];
  102. if(!empty($aParams) && is_array($aParams))
  103. $aData = array_merge($aData, $aParams);
  104. $sRv = bx_file_get_contents($sEndpoint, $aData, "post-json", ["Authorization: Bearer ".$sApiKey, 'Content-Type: application/json', 'OpenAI-Beta: assistants=v2']);
  105. $aRv = json_decode($sRv, true);
  106. if(isset($aRv['error'])) {
  107. //TODO: log error in AI related log file.
  108. return 'false';
  109. }
  110. return trim(str_replace(['```json', '```php', '```'], '', $aRv['choices'][0]['message']['content']));
  111. }
  112. public function callAutomator($sType, $aParams = [])
  113. {
  114. $sMethod = '_callAutomator' . bx_gen_method_name($sType);
  115. if(!method_exists($this, $sMethod))
  116. return false;
  117. return $this->$sMethod($aParams);
  118. }
  119. protected function _callAutomatorEvent($aParams = [])
  120. {
  121. if(!isset($aParams['automator'], $aParams['alert']) || !is_a($aParams['alert'], 'BxDolAlerts'))
  122. return false;
  123. $oAlert = &$aParams['alert'];
  124. $this->evalCode($aParams['automator'], true, ['alert' => $oAlert]);
  125. }
  126. protected function _callAutomatorScheduler($aParams = [])
  127. {
  128. if(!isset($aParams['automator']))
  129. return false;
  130. $this->evalCode($aParams['automator'], true);
  131. }
  132. public function evalCode($aAutomator, $isWriteLog = true, $aParams = null)
  133. {
  134. /*
  135. * TODO: Improve code evaluation.
  136. *
  137. ob_start();
  138. set_error_handler("evalErrorHandler");
  139. */
  140. try {
  141. $sCode = '';
  142. if ($aAutomator['type'] == 'scheduler'){
  143. $sCode = $aAutomator['code'] . '; onCron();';
  144. }
  145. if ($aAutomator['type'] == 'event'){
  146. $sCode = $aAutomator['code']. '; onAlert($aParams["alert"]->iObject , $aParams["alert"]->iSender , $aParams["alert"]->aExtras);';
  147. }
  148. eval($sCode);
  149. }
  150. catch (Exception $oException) {
  151. if ($isWriteLog){
  152. $this->writeLog($oException->getFile() . ':' . $oException->getLine() . ' ' . $oException->getMessage());
  153. }
  154. return $oException->getMessage();
  155. }
  156. finally {
  157. /*
  158. * TODO: Improve code evaluation.
  159. *
  160. $sOutput = ob_get_clean();
  161. if ($sOutput != '')
  162. return "Eval error: " . $sOutput;
  163. restore_error_handler();
  164. */
  165. }
  166. }
  167. private function writeLog($sString)
  168. {
  169. bx_log('sys_agents', $sString, BX_LOG_ERR);
  170. }
  171. }
  172. class EvalException extends Exception {}
  173. function evalErrorHandler($errno, $errstr, $errfile, $errline) {
  174. if (!(error_reporting() & $errno)) {
  175. // This error code is not included in error_reporting
  176. return false;
  177. }
  178. throw new EvalException($errstr, $errno);
  179. }