فهرست منبع

Ticket #4711 - Models.

AntonLV 2 سال پیش
والد
کامیت
e125c34a14

+ 212 - 0
ai/BxDolAI.php

@@ -0,0 +1,212 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+define('BX_DOL_AI_AUTOMATOR_EVENT', 'event');
+define('BX_DOL_AI_AUTOMATOR_SCHEDULER', 'scheduler');
+define('BX_DOL_AI_AUTOMATOR_WEBHOOK', 'webhook');
+
+define('BX_DOL_AI_AUTOMATOR_STATUS_AUTO', 'auto');
+define('BX_DOL_AI_AUTOMATOR_STATUS_MANUAL', 'manual');
+define('BX_DOL_AI_AUTOMATOR_STATUS_READY', 'ready');
+
+class BxDolAI extends BxDolFactory implements iBxDolSingleton
+{
+    protected $_oDb;
+    protected $_sPathInst;
+    protected $_iProfileId;
+    
+    protected $_aExcludeAlertUnits;
+
+    protected function __construct()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error ('Multiple instances are not allowed for the class: ' . get_class($this), E_USER_ERROR);
+
+        parent::__construct();
+
+        $this->_oDb = new BxDolAIQuery();
+        $this->_sPathInst = BX_DIRECTORY_PATH_ROOT . 'ai/instructions/';
+        $this->_iProfileId = (int)getParam('sys_profile_bot'); 
+
+        $this->_aExcludeAlertUnits = [
+            'system', 'module_template_method_call'
+        ];
+    }
+
+    /**
+     * Prevent cloning the instance
+     */
+    public function __clone()
+    {
+        if (isset($GLOBALS['bxDolClasses'][get_class($this)]))
+            trigger_error('Clone is not allowed for the class: ' . get_class($this), E_USER_ERROR);
+    }
+
+    /**
+     * Get singleton instance of the class
+     */
+    public static function getInstance()
+    {
+        if(!isset($GLOBALS['bxDolClasses'][__CLASS__]))
+            $GLOBALS['bxDolClasses'][__CLASS__] = new BxDolAI();
+
+        return $GLOBALS['bxDolClasses'][__CLASS__];
+    }
+
+    public function getProfileId()
+    {
+        return $this->_iProfileId;
+    }
+
+    public function getAutomatorInstructions($sType, $bIncludeCommon = false)
+    {
+        $sResult = file_get_contents($this->_sPathInst . $sType . '.html');
+        if($bIncludeCommon)
+            $sResult .= file_get_contents($this->_sPathInst. 'common.html');
+
+        return $sResult;
+    }
+    
+    public function getModel($iId)
+    {
+        $aModel = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $iId]);
+        if(!empty($aModel['params']))
+            $aModel['params'] = json_decode($aModel['params'], true);
+
+        return $aModel;
+    }
+
+    public function getAutomator($iId, $bFullInfo = false)
+    {
+        $aAutomator = $this->_oDb->getAutomatorsBy(['sample' => 'id' . ($bFullInfo ? '_full' : ''), 'id' => $iId]);
+        if(!empty($aAutomator['params']))
+            $aAutomator['params'] = json_decode($aAutomator['params'], true);
+        if($bFullInfo && !empty($aAutomator['model_params']))
+            $aAutomator['model_params'] = json_decode($aAutomator['model_params'], true);
+
+        return $aAutomator;
+    }
+    
+    public function getAutomatorsEvent($sUnit, $sAction)
+    {
+        if(in_array($sUnit, $this->_aExcludeAlertUnits))
+            return [];
+
+        return $this->_oDb->getAutomatorsBy([
+            'sample' => 'events', 
+            'alert_unit' => $sUnit,
+            'alert_action' => $sAction,
+            'active' => true
+        ]);
+    }
+    public function getAutomatorsScheduler()
+    {
+        $aAutomators = $this->_oDb->getAutomatorsBy(['sample' => 'schedulers', 'active' => true]);
+        foreach($aAutomators as &$aAutomator)
+            if(!empty($aAutomator['params']))
+                $aAutomator['params'] = json_decode($aAutomator['params'], true);
+
+        return $aAutomators;
+    }
+
+    public function chat($sEndpoint, $sModel, $sApiKey, $aParams, $aMessages)
+    {
+        $aData = [
+            'model' => $sModel,
+            'messages' => $aMessages
+        ];
+
+        if(!empty($aParams) && is_array($aParams))
+            $aData = array_merge($aData, $aParams);
+
+        $sRv = bx_file_get_contents($sEndpoint, $aData, "post-json", ["Authorization: Bearer ".$sApiKey, 'Content-Type: application/json', 'OpenAI-Beta: assistants=v2']);
+        $aRv = json_decode($sRv, true);
+
+        if(isset($aRv['error'])) {
+            //TODO: log error in AI related log file.
+            return 'false';
+        }
+
+        return trim(str_replace(['```json', '```php', '```'], '', $aRv['choices'][0]['message']['content']));
+    }
+
+    public function callAutomator($sType, $aParams = [])
+    {
+        $sMethod = '_callAutomator' . bx_gen_method_name($sType);
+        if(!method_exists($this, $sMethod))
+            return false;
+
+        return $this->$sMethod($aParams);
+    }
+
+    protected function _callAutomatorEvent($aParams = [])
+    {
+        if(!isset($aParams['automator'], $aParams['alert']) || !is_a($aParams['alert'], 'BxDolAlerts'))
+            return false;
+        
+        $oAlert = &$aParams['alert'];
+
+        $this->evalCode($aParams['automator'], true, ['alert' => $oAlert]);
+    }
+
+    protected function _callAutomatorScheduler($aParams = [])
+    {
+        if(!isset($aParams['automator']))
+            return false;
+        
+        $this->evalCode($aParams['automator'], true);
+    }
+    
+    
+    public function evalCode($aAutomator, $isWriteLog = true, $aParams = null)
+    {
+        ob_start();
+        set_error_handler("evalErrorHandler");
+        try{
+             $sCode = '';
+             if ($aAutomator['type'] == 'scheduler'){
+                 $sCode = $aAutomator['code'] . '; onCron();';
+             }
+             
+             if ($aAutomator['type'] == 'event'){
+                 $sCode = $aAutomator['code']. '; onAlert($aParams["alert"]->iObject , $aParams["alert"]->iSender , $aParams["alert"]->aExtras);';  
+             }
+             
+             
+             eval($sCode);
+            
+        }
+        catch (Exception $oException) {
+            if ($isWriteLog){
+                $this->writeLog($oException->getFile() . ':' . $oException->getLine() . ' ' . $oException->getMessage());
+            }
+            return $oException->getMessage();
+        } finally {
+             $sOutput = ob_get_clean();
+             if ($sOutput != '')
+                return "Eval error: " . $sOutput;
+            restore_error_handler();
+        }
+    }
+    
+    private function writeLog($sString)
+	{
+        bx_log('sys_agents', $sString);
+	}
+}
+
+class EvalException extends Exception {}
+
+function evalErrorHandler($errno, $errstr, $errfile, $errline) {
+    if (!(error_reporting() & $errno)) {
+        // This error code is not included in error_reporting
+        return false;
+    }
+    throw new EvalException($errstr, $errno);
+}

+ 13 - 8
inc/classes/BxDolAI.php

@@ -18,7 +18,6 @@ define('BX_DOL_AI_AUTOMATOR_STATUS_READY', 'ready');
 class BxDolAI extends BxDolFactory implements iBxDolSingleton
 {
     protected $_oDb;
-    protected $_sPathInst;
     protected $_iProfileId;
     
     protected $_aExcludeAlertUnits;
@@ -31,7 +30,7 @@ class BxDolAI extends BxDolFactory implements iBxDolSingleton
         parent::__construct();
 
         $this->_oDb = new BxDolAIQuery();
-        $this->_sPathInst = BX_DIRECTORY_PATH_ROOT . getParam('sys_agents_ai_inst_path');
+
         $this->_iProfileId = (int)getParam('sys_profile_bot'); 
 
         $this->_aExcludeAlertUnits = [
@@ -64,13 +63,9 @@ class BxDolAI extends BxDolFactory implements iBxDolSingleton
         return $this->_iProfileId;
     }
 
-    public function getAutomatorInstructions($sType, $bIncludeCommon = false)
+    public function getModels()
     {
-        $sResult = file_get_contents($this->_sPathInst . $sType . '.html');
-        if($bIncludeCommon)
-            $sResult .= file_get_contents($this->_sPathInst. 'common.html');
-
-        return $sResult;
+        return $aModel = $this->_oDb->getModelsBy(['sample' => 'all_pairs']);
     }
     
     public function getModel($iId)
@@ -81,6 +76,16 @@ class BxDolAI extends BxDolFactory implements iBxDolSingleton
 
         return $aModel;
     }
+    
+    public function getModelObject($iId = 0)
+    {
+        if(!$iId)
+            $iId = (int)getParam('sys_agents_model');
+        if(!$iId)
+            return false;
+
+        return BxDolAIModel::getObjectInstance($iId);
+    }   
 
     public function getAutomator($iId, $bFullInfo = false)
     {

+ 91 - 0
inc/classes/BxDolAIModel.php

@@ -0,0 +1,91 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolAIModel extends BxDol
+{
+    protected $_oDb;
+    protected $_iId;
+    protected $_sName;
+    protected $_sCaption;
+    protected $_sKey;
+    protected $_sParams;
+
+    public function __construct($aModel)
+    {
+        parent::__construct();
+
+        if(empty($aModel) || !is_array($aModel) || strcmp($aModel['name'], $this->_sName) != 0)
+            $this->_log("Unexpected value provided for the credentials");
+
+        $this->_oDb = new BxDolAIQuery();
+
+        $this->_iId = (int)$aModel['id'];
+        $this->_sName = $aModel['name'];
+        $this->_sCaption = _t($aModel['title']);
+        $this->_sKey = $aModel['key'];
+        $this->_sParams = !empty($aModel['params']) ? json_decode($aModel['params'], true) : [];
+    }
+
+    /**
+     * Get model object instance by model name
+     * @param $sName model name
+     * @return object instance or false on error
+     */
+    public static function getObjectInstance($iId)
+    {
+        $sPrefix = 'BxDolAIModel!';
+
+        if(isset($GLOBALS['bxDolClasses'][$sPrefix . $iId]))
+            return $GLOBALS['bxDolClasses'][$sPrefix . $iId];
+
+        $aModel = BxDolAIQuery::getModelObject($iId);
+        if(!$aModel || !is_array($aModel))
+            return false;
+
+        $sClass = 'BxDolAIModel';
+        if(!empty($aModel['class_name'])) {
+            $sClass = $aModel['class_name'];
+            if(!empty($aModel['class_file']))
+                require_once(BX_DIRECTORY_PATH_ROOT . $aModel['class_file']);
+        }
+
+        $o = new $sClass($aModel);
+        return ($GLOBALS['bxDolClasses'][$sPrefix . $iId] = $o);
+    }
+
+    public function getResponse($sType, $aMessage, $bInit = false)
+    {
+        // Should be overwritten to get call response.
+    }
+
+    public function call($aMessages, $aParams = [])
+    {
+        // Should be overwritten to process a call.
+    }
+
+    /**
+     * Internal methods.
+     */
+    protected function _log($mixedError, $bUseLog = false)
+    {
+        if($bUseLog)
+            bx_log('sys_agents', $mixedError);
+        else {
+            $sMessage = 'Error occurred';
+            if(is_string($mixedError))
+                $sMessage = $mixedError;
+            else if(is_array($mixedError) && isset($mixedError['message']))
+                $sMessage = $mixedError['message'];
+
+            throw new Exception($sMessage);
+        }
+
+        return false;
+    }    
+}

+ 84 - 0
inc/classes/BxDolAIModelGpt35.php

@@ -0,0 +1,84 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolAIModelGpt35 extends BxDolAIModel
+{
+    public static $NAME = 'gpt-3.5-turbo';
+
+    protected $_sEndpoint;
+    protected $_sPathInst;
+
+    public function __construct($aModel)
+    {
+        $this->_sName = self::$NAME;
+
+        parent::__construct($aModel);
+
+        $this->_sEndpoint = "https://api.openai.com/v1/chat/completions";
+        $this->_sPathInst = BX_DIRECTORY_PATH_ROOT . 'ai/instructions/';
+    }
+
+    public function getResponse($sType, $sMessage, $bInit = false)
+    {
+        $aMessages = [];
+
+        if($bInit)
+            $aMessages = [
+                ['role' => 'system', 'content' => $this->_getInstructions($sType . '_init')],
+                ['role' => 'user', 'content' => $sMessage]
+            ];
+        else
+            $aMessages = [
+                ['role' => 'system', 'content' => $this->_getInstructions($sType, true)],
+                ['role' => 'user', 'content' => $sMessage]
+            ];
+        
+
+        $sResponse = $this->call($aMessages);
+        if($sResponse == 'false')
+            return false;
+
+        return $sResponse;
+    }
+
+    public function call($aMessages, $aParams = [])
+    {
+        $aData = [
+            'model' => $this->_sName,
+            'messages' => $aMessages
+        ];
+
+        $aData = array_merge($aData, $this->_sParams);
+        if(!empty($aParams) && is_array($aParams))
+            $aData = array_merge($aData, $aParams);
+
+        $sResponse = bx_file_get_contents($this->_sEndpoint, $aData, "post-json", [
+            "Authorization: Bearer " . $this->_sKey, 
+            'Content-Type: application/json', 
+            'OpenAI-Beta: assistants=v1'
+        ]);
+
+        $aResponse = json_decode($sResponse, true);
+        if(isset($aResponse['error'])) {
+            $this->_log($aResponse['error']);
+            return 'false';
+        }
+
+        return trim(str_replace(['```json', '```php', '```'], '', $aResponse['choices'][0]['message']['content']));
+    }
+
+    protected function _getInstructions($sType, $bIncludeCommon = false)
+    {
+        $sResult = file_get_contents($this->_sPathInst . $sType . '.html');
+        if($bIncludeCommon)
+            $sResult .= file_get_contents($this->_sPathInst. 'common.html');
+
+        return $sResult;
+    }
+}

+ 12 - 10
inc/classes/BxDolAIQuery.php

@@ -14,6 +14,17 @@ class BxDolAIQuery extends BxDolDb
         parent::__construct();
     }
 
+    static public function getModelObject($iId)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $aModel = $oDb->getRow("SELECT * FROM `sys_agents_models` WHERE `id` = :id", ['id' => $iId]);
+        if(!$aModel || !is_array($aModel))
+            return false;
+
+        return $aModel;
+    }
+
     static public function getProviderObject($iId)
     {
         $oDb = BxDolDb::getInstance();
@@ -59,19 +70,10 @@ class BxDolAIQuery extends BxDolDb
                 $sWhereClause .= " AND `id`=:id";
                 break;
 
-            case 'name':
-            	$aMethod['name'] = 'getRow';
-            	$aMethod['params'][1] = [
-                    'name' => $aParams['name']
-                ];
-
-                $sWhereClause .= " AND `name`=:name";
-                break;
-
             case 'all_pairs':
                 $aMethod['name'] = 'getPairs';
                 $aMethod['params'][1] = 'id';
-                $aMethod['params'][2] = 'name';
+                $aMethod['params'][2] = 'title';
                 break;
         }
 

+ 10 - 7
install/sql/system.sql

@@ -824,7 +824,7 @@ INSERT INTO `sys_options_categories`(`type_id`, `name`, `caption`, `hidden`, `or
 SET @iCategoryId = LAST_INSERT_ID();
 
 INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `extra`, `check`, `check_error`, `order`) VALUES
-(@iCategoryId, 'sys_agents_ai_inst_path', '_adm_stg_cpt_option_sys_agents_ai_inst_path', 'ai/instructions/', 'digit', '', '', '', 0),
+(@iCategoryId, 'sys_agents_model', '_adm_stg_cpt_option_sys_agents_model', '', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:24:"get_options_agents_model";s:5:"class";s:13:"TemplServices";}', '', '', 0);
 (@iCategoryId, 'sys_agents_url', '_adm_stg_cpt_option_sys_agents_url', '', 'digit', '', '', '', 10),
 (@iCategoryId, 'sys_agents_profile', '_adm_stg_cpt_option_sys_agents_profile', '', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:26:"get_options_agents_profile";s:5:"class";s:13:"TemplServices";}', '', '', 20);
 
@@ -6290,16 +6290,19 @@ CREATE TABLE `sys_api_origins` (
 
 CREATE TABLE IF NOT EXISTS `sys_agents_models` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
-  `name` varchar(64) NOT NULL default '',
-  `url` varchar(255) NOT NULL default '',
+  `name` varchar(32) NOT NULL default '',
+  `title` varchar(64) NOT NULL default '',
   `key` varchar(64) NOT NULL default '',
-  `model` varchar(32) NOT NULL default '',
   `params` text NOT NULL,
-  PRIMARY KEY (`id`)
+  `class_name` varchar(128) NOT NULL default '',
+  `class_file` varchar(255) NOT NULL  default '',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name`(`name`)
 );
 
-INSERT INTO `sys_agents_models`(`name`, `url`, `key`, `model`, `params`) VALUES
-('default', '', '', '', '');
+INSERT INTO `sys_agents_models`(`name`, `title`, `key`, `params`, `class_name`, `class_file`) VALUES
+('gpt-3.5-turbo', 'GPT-3.5-TURBO', '', '{"temperature":0.1}', 'BxDolAIModelGpt35', ''),
+('gpt-4o', 'GPT-4.O', '', '{"temperature":0.1}', 'BxDolAIModelGpt40', '');
 
 CREATE TABLE IF NOT EXISTS `sys_agents_automators` (
   `id` int(11) NOT NULL AUTO_INCREMENT,

+ 1 - 1
modules/boonex/english/data/langs/system/en.xml

@@ -1758,7 +1758,7 @@
     <string name="_adm_stg_cpt_option_sys_api_conn_in_prof_units"><![CDATA[Use connections lists in profiles/groups units]]></string>
     <string name="_adm_stg_cpt_option_sys_api_url_root_email"><![CDATA[Site main URL in email notifications]]></string>
     <string name="_adm_stg_cpt_option_sys_api_url_root_push"><![CDATA[Site main URL in push notifications]]></string>
-    <string name="_adm_stg_cpt_option_sys_agents_ai_inst_path"><![CDATA[Path to a folder with AI instructions files]]></string>
+    <string name="_adm_stg_cpt_option_sys_agents_model"><![CDATA[Default model]]></string>
     <string name="_adm_stg_cpt_option_sys_agents_url"><![CDATA[Endpoint URL]]></string>
     <string name="_adm_stg_cpt_option_sys_agents_profile"><![CDATA[Profile]]></string>   
     <string name="_adm_stg_cpt_option_sys_viewport_meta_tag"><![CDATA[Viewport meta tag]]></string>

+ 1 - 1
modules/boonex/russian/data/langs/system/ru.xml

@@ -1734,7 +1734,7 @@
     <string name="_adm_stg_cpt_option_sys_api_conn_in_prof_units"><![CDATA[Использовать списки связей в блоках профилей/групп.]]></string>
     <string name="_adm_stg_cpt_option_sys_api_url_root_email"><![CDATA[Основной URL-адрес сайта в уведомлениях по электронной почте]]></string>
     <string name="_adm_stg_cpt_option_sys_api_url_root_push"><![CDATA[Основной URL-адрес сайта в push-уведомлениях]]></string>
-    <string name="_adm_stg_cpt_option_sys_agents_ai_inst_path"><![CDATA[Путь к папке с файлами инструкций AI]]></string>
+    <string name="_adm_stg_cpt_option_sys_agents_model"><![CDATA[Модель по умолчанию]]></string>
     <string name="_adm_stg_cpt_option_sys_agents_url"><![CDATA[URL конечной точки]]></string>
     <string name="_adm_stg_cpt_option_sys_agents_profile"><![CDATA[Профиль]]></string>   
     <string name="_adm_stg_cpt_option_sys_viewport_meta_tag"><![CDATA[Метатег области просмотра]]></string>

+ 6 - 20
studio/template/scripts/BxBaseStudioAgentsAutomators.php

@@ -55,21 +55,14 @@ class BxBaseStudioAgentsAutomators extends BxDolStudioAgentsAutomators
             $sMessageAdd = '';
             $sMessageResponse = '';
 
-            $oAI = BxDolAI::getInstance();
-
-            $aMessages = [
-                ['role' => 'system', 'content' => $oAI->getAutomatorInstructions($sType . '_init')],
-                ['role' => 'user', 'content' => $sMessage]
-            ];
-
-            $aModel = $oAI->getModel($iModel);
+            $oAIModel = BxDolAI::getInstance()->getModelObject($iModel);
 
             $bIsValid = true;
             switch($sType) {
                 case BX_DOL_AI_AUTOMATOR_EVENT:
-                    $sResponse = $oAI->chat($aModel['url'], $aModel['model'], $aModel['key'], $aModel['params'], $aMessages);
-                    if($sResponse != 'false') {
+                    if(($sResponse = $oAIModel->getResponse($sType, $sMessage, true)) !== false) {
                         $aResponse = json_decode($sResponse, true);
+
                         $aValsToAdd = array_merge($aValsToAdd, [
                             'alert_unit' => $aResponse['alert_unit'],
                             'alert_action' => $aResponse['alert_action'],
@@ -84,8 +77,7 @@ class BxBaseStudioAgentsAutomators extends BxDolStudioAgentsAutomators
                     break;
 
                 case BX_DOL_AI_AUTOMATOR_SCHEDULER:
-                    $sResponse = $oAI->chat($aModel['url'], $aModel['model'], $aModel['key'], $aModel['params'], $aMessages);
-                    if($sResponse != 'false') {
+                    if(($sResponse = $oAIModel->getResponse($sType, $sMessage, true)) !== false) {
                         $aValsToAdd['params'] = json_encode(['scheduler_time' => $sResponse]);
                     }
                     else {
@@ -96,13 +88,7 @@ class BxBaseStudioAgentsAutomators extends BxDolStudioAgentsAutomators
             }
 
             if($bIsValid) {
-                $aMessages = [
-                    ['role' => 'system', 'content' => $oAI->getAutomatorInstructions($sType, true)],
-                    ['role' => 'user', 'content' => $sMessage . $sMessageAdd]
-                ];
-
-                $sResponse = $oAI->chat($aModel['url'], $aModel['model'], $aModel['key'], $aModel['params'], $aMessages);
-                if($sResponse != 'false') {
+                if(($sResponse = $oAIModel->getResponse($sType, $sMessage . $sMessageAdd)) !== false) {
                     $sMessageResponse = $sResponse;
                 }
                 else {
@@ -249,7 +235,7 @@ class BxBaseStudioAgentsAutomators extends BxDolStudioAgentsAutomators
     {
         $aModel = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $mixedValue]);
         if(!empty($aModel) && is_array($aModel))
-            $mixedValue = $aModel['name'];
+            $mixedValue = $aModel['title'];
 
         return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
     }

+ 5 - 0
template/scripts/BxBaseServices.php

@@ -1289,6 +1289,11 @@ class BxBaseServices extends BxDol implements iBxDolProfileService
         return $aResults;
     }
 
+    public function serviceGetOptionsAgentsModel()
+    {
+        return ['' => _t('_Select_one')] + BxDolAI::getInstance()->getModels();
+    }
+
     public function serviceGetOptionsAgentsProfile($bSelectOne = true)
     {
         $aResult = [];