Explorar o código

Ticket #4711 - Models.

AntonLV %!s(int64=2) %!d(string=hai) anos
pai
achega
b00310ba3e

+ 8 - 3
inc/classes/BxDolAI.php

@@ -62,12 +62,17 @@ class BxDolAI extends BxDolFactory implements iBxDolSingleton
     {
         return $this->_iProfileId;
     }
+    
+    public function getDefaultModel()
+    {
+        return (int)getParam('sys_agents_model');
+    }
 
     public function getModels()
     {
         return $aModel = $this->_oDb->getModelsBy(['sample' => 'all_pairs']);
     }
-    
+
     public function getModel($iId)
     {
         $aModel = $this->_oDb->getModelsBy(['sample' => 'id', 'id' => $iId]);
@@ -76,11 +81,11 @@ class BxDolAI extends BxDolFactory implements iBxDolSingleton
 
         return $aModel;
     }
-    
+
     public function getModelObject($iId = 0)
     {
         if(!$iId)
-            $iId = (int)getParam('sys_agents_model');
+            $iId = $this->getDefaultModel();
         if(!$iId)
             return false;
 

+ 19 - 6
inc/classes/BxDolAIModel.php

@@ -14,7 +14,7 @@ class BxDolAIModel extends BxDol
     protected $_sName;
     protected $_sCaption;
     protected $_sKey;
-    protected $_sParams;
+    protected $_aParams;
 
     public function __construct($aModel)
     {
@@ -29,7 +29,7 @@ class BxDolAIModel extends BxDol
         $this->_sName = $aModel['name'];
         $this->_sCaption = _t($aModel['title']);
         $this->_sKey = $aModel['key'];
-        $this->_sParams = !empty($aModel['params']) ? json_decode($aModel['params'], true) : [];
+        $this->_aParams = !empty($aModel['params']) ? json_decode($aModel['params'], true) : [];
     }
 
     /**
@@ -58,15 +58,28 @@ class BxDolAIModel extends BxDol
         $o = new $sClass($aModel);
         return ($GLOBALS['bxDolClasses'][$sPrefix . $iId] = $o);
     }
+    
+    public function getParams()
+    {
+        return $this->_aParams;
+    }
 
-    public function getResponse($sType, $aMessage, $bInit = false)
+    public function setParams($aParams)
     {
-        // Should be overwritten to get call response.
+        if(empty($aParams) || !is_array($aParams))
+            return;
+
+        $this->_aParams = array_merge($this->_aParams, $aParams);
     }
 
-    public function call($aMessages, $aParams = [])
+    public function getResponseInit($sType, $aMessage, $aParams = [])
     {
-        // Should be overwritten to process a call.
+        // Should be overwritten to get init call response.
+    }
+
+    public function getResponse($sType, $aMessage, $aParams = [])
+    {
+        // Should be overwritten to get call response.
     }
 
     /**

+ 43 - 11
inc/classes/BxDolAIModelGpt35.php

@@ -24,18 +24,49 @@ class BxDolAIModelGpt35 extends BxDolAIModel
         $this->_sPathInst = BX_DIRECTORY_PATH_ROOT . 'ai/instructions/';
     }
 
-    public function getResponse($sType, $mixedMessage, $bInit = false)
+    public function getResponseInit($sType, $sMessage, $aParams = [])
     {
-        $aMessages = [];
+        $aMessages = [
+            ['role' => 'system', 'content' => $this->_getInstructions($sType . '_init')],
+            ['role' => 'user', 'content' => $sMessage]
+        ];
 
-        if($bInit)
-            $aMessages = [
-                ['role' => 'system', 'content' => $this->_getInstructions($sType . '_init')]
-            ];
-        else
-            $aMessages = [
-                ['role' => 'system', 'content' => $this->_getInstructions($sType, true)]
-            ];
+        $sResponse = $this->call($aMessages);
+        if($sResponse == 'false')
+            return false;
+
+        $mixedResult = [];
+        switch($sType) {
+            case BX_DOL_AI_AUTOMATOR_EVENT:
+                $aResponse = json_decode($sResponse, true);
+
+                $mixedResult = [
+                    'alert_unit' => $aResponse['alert_unit'],
+                    'alert_action' => $aResponse['alert_action'],
+                    'params' => [
+                        'trigger' => $aResponse['trigger']
+                    ]
+                ];
+                break;
+
+            case BX_DOL_AI_AUTOMATOR_SCHEDULER:
+                $mixedResult = [
+                    'params' => [
+                        'scheduler_time' => $sResponse
+                    ]
+                ];
+                break;
+        }
+        
+
+        return $mixedResult;
+    }
+
+    public function getResponse($sType, $mixedMessage, $aParams = [])
+    {
+        $aMessages = [
+            ['role' => 'system', 'content' => $this->_getInstructions($sType, true)]
+        ];
         
         if(is_array($mixedMessage)) {
             foreach($mixedMessage as $aMessage)
@@ -61,7 +92,8 @@ class BxDolAIModelGpt35 extends BxDolAIModel
             'messages' => $aMessages
         ];
 
-        $aData = array_merge($aData, $this->_sParams);
+        if(!empty($this->_aParams['call']) && is_array($this->_aParams['call']))
+            $aData = array_merge($aData, $this->_aParams['call']);
         if(!empty($aParams) && is_array($aParams))
             $aData = array_merge($aData, $aParams);
 

+ 183 - 0
inc/classes/BxDolAIModelGpt40.php

@@ -0,0 +1,183 @@
+<?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 BxDolAIModelGpt40 extends BxDolAIModel
+{
+    public static $NAME = 'gpt-4o';
+
+    protected $_sEndpoint;
+    protected $_sEndpointRuns;
+    protected $_sEndpointMessages;
+
+    public function __construct($aModel)
+    {
+        $this->_sName = self::$NAME;
+
+        parent::__construct($aModel);
+
+        $this->_sEndpoint = "https://api.openai.com/v1/threads";
+        $this->_sEndpointRuns = $this->_sEndpoint . '/%s/runs';
+        $this->_sEndpointRunsCheck = $this->_sEndpoint . '/%s/runs/%s';
+        $this->_sEndpointMessages = $this->_sEndpoint . '/%s/messages';
+    }
+
+    public function getResponseInit($sType, $sMessage, $aParams = [])
+    {        
+        $aResponse = $this->call(['messages' => [['role' => 'user', 'content' => $sMessage]]]);
+        if(!isset($aResponse['id'], $aResponse['object']) || $aResponse['object'] != 'thread')
+            return false;
+
+        $sThreadId = $aResponse['id'];
+
+        $aResponse = $this->callRuns($sThreadId, [
+            'assistant_id' => $this->_getAssistantId($sType . '_init')
+        ]);
+
+        $sRunId = $aResponse['id'];
+        while($aResponse['status'] != 'completed') {
+            sleep(2);
+
+            $aResponse = $this->callRunsCheck($sThreadId, $sRunId);
+        }
+
+        $sResponse = $this->getMessages($sThreadId);
+
+        $mixedResult = [];
+        switch($sType) {
+            case BX_DOL_AI_AUTOMATOR_EVENT:
+                //TODO: previously we had an array here with 'alert_unit', 'alert_action' and 'trigger';
+                $mixedResult = [
+                    'alert_unit' => $aResponse['alert_unit'],
+                    'alert_action' => $aResponse['alert_action'],
+                    'params' => [
+                        'thread_id' => $sThreadId,
+                        'trigger' => $aResponse['trigger']
+                    ]
+                ];
+                break;
+
+            case BX_DOL_AI_AUTOMATOR_SCHEDULER:
+                $mixedResult = [
+                    'params' => [
+                        'thread_id' => $sThreadId,
+                        'scheduler_time' => $sResponse
+                    ]
+                ];
+                break;
+        }
+
+        return $mixedResult;
+    }
+
+    public function getResponse($sType, $sMessage, $aParams = [])
+    {
+        if(empty($aParams['thread_id']))
+            return false;
+
+        if(is_array($sMessage))
+            $sMessage = end($sMessage)['content'];
+
+        $sThreadId = $aParams['thread_id'];
+        if(!$this->callMessages($sThreadId, ['role' => 'user', 'content' => $sMessage]))
+            return false;
+
+        $aResponse = $this->callRuns($sThreadId, [
+            'assistant_id' => $this->_getAssistantId($sType)
+        ]);
+
+        $sRunId = $aResponse['id'];
+        while($aResponse['status'] != 'completed') {
+            sleep(2);
+
+            $aResponse = $this->callRunsCheck($sThreadId, $sRunId);
+        }
+
+        return $this->getMessages($sThreadId);
+    }
+
+    public function call($aParams = [])
+    {
+        $aData = [];
+        if(!empty($this->_aParams['call']) && is_array($this->_aParams['call']))
+            $aData = array_merge($aData, $this->_aParams['call']);
+        if(!empty($aParams) && is_array($aParams))
+            $aData = array_merge($aData, $aParams);
+
+        return $this->_call($this->_sEndpoint, $aData);
+        
+    }
+
+    public function callRuns($sThreadId, $aParams = [])
+    {
+        $aData = [];
+        if(!empty($this->_aParams['call_runs']) && is_array($this->_aParams['call_runs']))
+            $aData = array_merge($aData, $this->_aParams['call_runs']);
+        if(!empty($aParams) && is_array($aParams))
+            $aData = array_merge($aData, $aParams);
+
+        return $this->_call(sprintf($this->_sEndpointRuns, $sThreadId), $aData);
+    }
+    
+    public function callRunsCheck($sThreadId, $sRunId)
+    {
+        return $this->_call(sprintf($this->_sEndpointRunsCheck, $sThreadId, $sRunId), [], 'get');
+    }
+    
+    public function callMessages($sThreadId, $aParams = [])
+    {
+        $aData = [];
+        if(!empty($this->_aParams['call_messages']) && is_array($this->_aParams['call_messages']))
+            $aData = array_merge($aData, $this->_aParams['call_messages']);
+        if(!empty($aParams) && is_array($aParams))
+            $aData = array_merge($aData, $aParams);
+
+        $mixedResponse = $this->_call(sprintf($this->_sEndpointMessages, $sThreadId), $aData);
+        if($mixedResponse !== false)
+            $mixedResponse = $mixedResponse['content'][0]['text']['value'];
+
+        return $mixedResponse;
+    }
+
+    public function getMessages($sThreadId, $aParams = [])
+    {
+        $aData = [];
+        if(!empty($this->_aParams['get_messages']) && is_array($this->_aParams['get_messages']))
+            $aData = array_merge($aData, $this->_aParams['get_messages']);
+        if(!empty($aParams) && is_array($aParams))
+            $aData = array_merge($aData, $aParams);
+
+        $mixedResponse = $this->_call(sprintf($this->_sEndpointMessages, $sThreadId), $aData, "get-json");
+        if($mixedResponse !== false)
+            $mixedResponse = trim(str_replace(['```json', '```php', '```'], '', $mixedResponse['data'][0]['content'][0]['text']['value']));
+
+        return $mixedResponse;
+    }
+
+    protected function _call($sEndpoint, $aData, $sMethod = "post-json")
+    {
+        $sResponse = bx_file_get_contents($sEndpoint, $aData, $sMethod, [
+            "Authorization: Bearer " . $this->_sKey, 
+            'Content-Type: application/json', 
+            'OpenAI-Beta: assistants=v2'
+        ]);
+
+        $aResponse = json_decode($sResponse, true);
+        if(isset($aResponse['error'])) {
+            $this->_log($aResponse['error']);
+            return false;
+        }
+
+        return $aResponse;
+    }
+
+    protected function _getAssistantId($sType)
+    {
+        return $this->_aParams['assistants'][$sType];
+    }
+}

+ 1 - 1
inc/classes/BxDolAIQuery.php

@@ -106,7 +106,7 @@ class BxDolAIQuery extends BxDolDb
                     'id' => $aParams['id']
                 ];
 
-                $sSelectClause .= ", `tam`.`name` AS `model_name`, `tam`.`url` AS `model_url`, `tam`.`key` AS `model_key`, `tam`.`model` AS `model_model`, `tam`.`params` AS `model_params`";
+                $sSelectClause .= ", `tam`.`name` AS `model_name`, `tam`.`title` AS `model_title`, `tam`.`key` AS `model_key`, `tam`.`params` AS `model_params`";
                 $sJoinClause .= " LEFT JOIN `sys_agents_models` AS `tam` ON `taa`.`model_id`=`tam`.`id`";
                 $sWhereClause .= " AND `taa`.`id`=:id";
                 break;

+ 2 - 2
install/sql/system.sql

@@ -6301,8 +6301,8 @@ CREATE TABLE IF NOT EXISTS `sys_agents_models` (
 );
 
 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', '');
+('gpt-3.5-turbo', 'GPT-3.5-TURBO', '', '{"call":{"temperature":0.1}}', 'BxDolAIModelGpt35', ''),
+('gpt-4o', 'GPT-4.O', '', '{"call":{},"assistants":{"event_init":"asst_HcEyaghqWZefkAyoEML40joY","event":"asst_wqaXtKjcsBKceMtJ2NxID2LT","scheduler_init":"asst_kEbDH1hUy2Y45nOKk9jaSTB8","scheduler":"asst_M6zOv4osQwZmRItaiYptjjOS"}}', 'BxDolAIModelGpt40', '');
 
 CREATE TABLE IF NOT EXISTS `sys_agents_automators` (
   `id` int(11) NOT NULL AUTO_INCREMENT,

+ 2 - 2
studio/classes/BxDolStudioAgentsAutomatorsCmts.php

@@ -193,8 +193,8 @@ class BxDolStudioAgentsAutomatorsCmts extends BxTemplCmts
                 'content' => $aComment['cmt_text']
             ];
 
-        $oAIModel = $this->_oAI->getModel($aAutomator['model_id']);
-        if(($sResponse = $oAIModel->getResponse($aAutomator['type'], $aMessages)) !== false) {
+        $oAIModel = $this->_oAI->getModelObject($aAutomator['model_id']);
+        if(($sResponse = $oAIModel->getResponse($aAutomator['type'], $aMessages, $aAutomator['params'])) !== false) {
             $mixedResultAuto = $this->addAuto([
                 'cmt_author_id' => $this->_iProfileIdAi,
                 'cmt_parent_id' => 0,

+ 17 - 13
studio/template/scripts/BxBaseStudioAgentsAutomators.php

@@ -58,17 +58,17 @@ class BxBaseStudioAgentsAutomators extends BxDolStudioAgentsAutomators
             $oAIModel = BxDolAI::getInstance()->getModelObject($iModel);
 
             $bIsValid = true;
+            $aResponseInit = [];
             switch($sType) {
                 case BX_DOL_AI_AUTOMATOR_EVENT:
-                    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'],
-                            'params' => json_encode(['trigger' => $aResponse['trigger']])
-                        ]);
-                        $sMessageAdd = $aResponse['trigger'];
+                    if(($aResponseInit = $oAIModel->getResponseInit($sType, $sMessage)) !== false) {
+                        $oAIModel->setParams($aResponseInit['params']);
+
+                        $sMessageAdd = $aResponseInit['params']['trigger'];
+
+                        $aValsToAdd = array_merge($aValsToAdd, $aResponseInit);
+                        if(!empty($aValsToAdd['params']) && is_array($aValsToAdd['params']))
+                            $aValsToAdd['params'] = json_encode($aValsToAdd['params']);
                     }
                     else {
                         $oForm->aInputs['message']['error'] = _t('_sys_agents_automators_err_event_not_found');
@@ -77,8 +77,12 @@ class BxBaseStudioAgentsAutomators extends BxDolStudioAgentsAutomators
                     break;
 
                 case BX_DOL_AI_AUTOMATOR_SCHEDULER:
-                    if(($sResponse = $oAIModel->getResponse($sType, $sMessage, true)) !== false) {
-                        $aValsToAdd['params'] = json_encode(['scheduler_time' => $sResponse]);
+                    if(($aResponseInit = $oAIModel->getResponseInit($sType, $sMessage)) !== false) {
+                        $oAIModel->setParams($aResponseInit['params']);
+
+                        $aValsToAdd = array_merge($aValsToAdd, $aResponseInit);
+                        if(!empty($aValsToAdd['params']) && is_array($aValsToAdd['params']))
+                            $aValsToAdd['params'] = json_encode($aValsToAdd['params']);
                     }
                     else {
                         $oForm->aInputs['message']['error'] = _t('_sys_agents_automators_err_event_not_found');
@@ -88,7 +92,7 @@ class BxBaseStudioAgentsAutomators extends BxDolStudioAgentsAutomators
             }
 
             if($bIsValid) {
-                if(($sResponse = $oAIModel->getResponse($sType, $sMessage . $sMessageAdd)) !== false) {
+                if(($sResponse = $oAIModel->getResponse($sType, $sMessage . $sMessageAdd, $oAIModel->getParams())) !== false) {
                     $sMessageResponse = $sResponse;
                 }
                 else {
@@ -348,7 +352,7 @@ class BxBaseStudioAgentsAutomators extends BxDolStudioAgentsAutomators
                     'name' => 'model_id',
                     'caption' => _t('_sys_agents_automators_field_model_id'),
                     'info' => '',
-                    'value' => isset($aAutomator['model_id']) ? $aAutomator['model_id'] : 0,
+                    'value' => isset($aAutomator['model_id']) ? $aAutomator['model_id'] : BxDolAI::getInstance()->getDefaultModel(),
                     'values' => $this->_oDb->getModelsBy(['sample' => 'all_pairs']),
                     'required' => '1',
                     'db' => [