ShuanghongS 6 ay önce
ebeveyn
işleme
77528f656e

+ 10 - 4
main_new_version.php

@@ -18,6 +18,8 @@ include 'service/column.class.php';
 include 'service/ajax.class.php';
 include 'service/login.class.php';
 include 'service/tools.class.php';
+include 'service/robot.class.php';
+include 'service/AIClientFactory.php';
 
 //为了调用,临时做一个登录动作  如果是正式版 要注释掉菜单System Settings
  //$_POST['uname'] = "ra.admin";
@@ -101,11 +103,12 @@ switch ($action) {
             //     "children"=>array(array("index" =>$index.'-1',"label" =>"Operation Log","path"=>"/Operationlog")));
             $systemManagement = array("index"=>"$index","label"=>"System Management","icon"=>"icon_system__management_fill_b","type"=>"list"); 
             $children  = array(); 
-            //$children[] = array("index" =>$index.'-1',"label" =>"System Message","path"=>"/system-message");
-            //$children[] = array("index" =>$index.'-2',"label" =>"System Settings","path"=>"/SystemSettings");  
+            $children[] = array("index" =>$index.'-1',"label" =>"System Message","path"=>"/system-message");
+            $children[] = array("index" =>$index.'-2',"label" =>"System Settings","path"=>"/SystemSettings");  
             //只有chud的账户可以看日志记录
             if(_getLoginName() == "chud" || _getLoginName() == "IT.Andywu" || _getLoginName() == "ra.admin"){
-                $children[] = array("index" =>$index.'-3',"label" =>"Operation Log","path"=>"/Operationlog");  
+                $children[] = array("index" =>$index.'-3',"label" =>"Operation Log","path"=>"/Operationlog");
+                //$children[] = array("index" =>$index.'-4',"label" =>"Prompt Configuration","path"=>"/PromptConfiguration");  
             }
             $systemManagement["children"] = $children;
             if (!empty($children)){
@@ -773,7 +776,10 @@ switch ($action) {
         break;    
     case 'tools':
         tools::getInstance()->markSystem();
-        break; 
+        break;
+    case 'robot':
+        robot::getInstance()->robot_prompt_configuration();
+        break;     
     case 'system_setting':
         tools::getInstance()->user_system_setting();
         break;

+ 220 - 0
service/AIClientFactory.php

@@ -0,0 +1,220 @@
+<?php
+
+class AIClientFactory
+{
+
+    public static function create($model, $config, $systemPrompt, $message, $history = [])
+    {
+        $instance = new self(); // 或 new MyClass();
+        if ($model == 'claude') {
+            return $instance->Claude37ClientSendMessage($config, $systemPrompt, $message, $history);
+        } elseif ($model == 'deepseek') {
+            return $instance->DeepSeekClientSendMessage($config, $systemPrompt, $message, $history);
+        }
+        return ['success' => false, 'error' => 'Invalid model'];
+    }
+
+    /**
+     * Send a message to the Claude API
+     * 
+     * @param string $message The user message
+     * @param array $history Previous conversation history
+     * @return array The API response
+     */
+    private function Claude37ClientSendMessage($config, $systemPrompt, $message, $history = [])
+    {
+        // Format conversation history for Claude API
+        //$messages = AIClientFactory::formatHistory($history);
+
+        // Add the current user message
+        $messages[] = [
+            'role' => 'user',
+            'content' => $message
+        ];
+
+        // Prepare request data
+        $data = [
+            'model' => $config['model'],
+            'messages' => $messages,
+            'system' => $systemPrompt,
+            'max_tokens' => $config['maxTokens'],
+            'temperature' => $config['temperature'],
+            'top_p' => $config['topP']
+        ];
+
+        // Prepare headers
+        $headers = [
+            'Content-Type: application/json',
+            'x-api-key: ' . $config['apiKey'],
+            'anthropic-version: 2023-06-01'
+        ];
+
+        try {
+            // Make the request
+            $response = $this->makeRequest($config['apiUrl'], $data, $headers);
+
+            // Extract the assistant's message
+            if (isset($response['content']) && !empty($response['content'])) {
+                $content = '';
+                foreach ($response['content'] as $part) {
+                    if ($part['type'] === 'text') {
+                        $content .= $part['text'];
+                    }
+                }
+
+                // Return formatted response
+                return [
+                    'success' => true,
+                    'message' => $content,
+                    'model' => 'claude',
+                    'full_response' => $response
+                ];
+            } else {
+                throw new Exception('Invalid response format from Claude API');
+            }
+        } catch (Exception $e) {
+            // Log and return error
+            error_log('Claude 3.7', $e->getMessage());
+
+            return [
+                'success' => false,
+                'error' => $e->getMessage(),
+                'model' => 'claude'
+            ];
+        }
+    }
+
+    /**
+     * Send a message to the DeepSeek API
+     *
+     * @param string $message The user message
+     * @param array $history Previous conversation history
+     * @return array The API response
+     */
+    private function DeepSeekClientSendMessage($config, $systemPrompt, $message, $history = [])
+    {
+        // Format conversation history for DeepSeek API
+        //$messages = $this->formatHistory($history);
+        $messages = [];
+
+        // Add system message at the beginning
+        $messages = array_merge([
+            ['role' => 'system', 'content' => $systemPrompt]
+        ], $messages);
+
+        // Add the current user message
+        $messages[] = [
+            'role' => 'user',
+            'content' => $message
+        ];
+
+        // Prepare request data
+        $data = [
+            'model' => $config['model'],
+            'messages' => $messages,
+            'max_tokens' => $config['maxTokens'],
+            'temperature' => $config['temperature'],
+            'top_p' => $config['topP']
+        ];
+
+        // Prepare headers
+        $headers = [
+            'Content-Type: application/json',
+            'Authorization: Bearer ' . $config['apiKey']
+        ];
+
+        try {
+            // Make the request
+            $response = $this->makeRequest($config['apiUrl'], $data, $headers);
+
+            // Extract the assistant's message
+            if (isset($response['choices'][0]['message']['content'])) {
+                $content = $response['choices'][0]['message']['content'];
+
+                // Return formatted response
+                return [
+                    'success' => true,
+                    'message' => $content,
+                    'model' => 'deepseek',
+                    'full_response' => $response
+                ];
+            } else {
+                throw new Exception('Invalid response format from DeepSeek API');
+            }
+        } catch (Exception $e) {
+            // Log and return error
+            error_log('DeepSeek', $e->getMessage());
+
+            return [
+                'success' => false,
+                'error' => $e->getMessage(),
+                'model' => 'deepseek'
+            ];
+        }
+    }
+
+
+    private function makeRequest($url, $data, $headers = [])
+    {
+        $ch = curl_init($url);
+
+        // Set common cURL options
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_POST, true);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
+
+        // Send the request
+        $response = curl_exec($ch);
+        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+        $error = curl_error($ch);
+
+        curl_close($ch);
+
+        // Handle errors
+        if ($error) {
+            error_log("cURL error: $url, $error");
+            throw new Exception("API request failed: $error");
+        }
+
+        // Decode response
+        $responseData = json_decode($response, true);
+
+        if ($httpCode >= 400) {
+            $errorMsg = isset($responseData['error']['message'])
+                ? $responseData['error']['message']
+                : "HTTP error code: $httpCode";
+
+            error_log($url, $errorMsg, $responseData);
+            throw new Exception("API error: $errorMsg");
+        }
+
+        return $responseData;
+    }
+
+    /* Format conversation history for Claude API
+    * 
+    * @param array $history Conversation history
+    * @return array Formatted history
+    */
+    private function formatHistory($history)
+    {
+        $messages = [];
+
+        foreach ($history as $item) {
+            if ($item['role'] === 'user') {
+                $messages[] = [
+                    'role' => 'user',
+                    'content' => $item['content']
+                ];
+            } elseif ($item['role'] === 'assistant') {
+                $messages[] = [
+                    'role' => 'assistant',
+                    'content' => $item['content']
+                ];
+            }
+        }
+
+        return $messages;
+    }
+}

+ 1 - 1
service/ocean_order.class.php

@@ -1608,7 +1608,7 @@ class ocean_order {
             if (!empty($isf_ss)) {
                 $ss = $isf_ss;
                 $len = strlen($ss);
-                $b = substr($ss, $len - 7) . substr($ss, 0, $len - 7);
+                    $b = substr($ss, $len - 7) . substr($ss, 0, $len - 7);
 
                 if (empty($b)){
 				    $isfLog["msg"] = "Origin have not filed ISF, no data found";

+ 325 - 0
service/robot.class.php

@@ -0,0 +1,325 @@
+<?php
+
+if (!defined('IN_ONLINE')) {
+    exit('Access Denied');
+}
+
+/**
+ * Description of robot
+ *
+ * @author Administrator
+ */
+class robot{
+
+    private static $_robot;
+
+    function __construct() {  
+       
+    }
+
+    public static function getInstance() {
+        global $memory_limit;
+        $memory_limit = ini_get("memory_limit");
+        ini_set("memory_limit", '2048M');
+        if (!self::$_robot) {
+            $c = __CLASS__;
+            self::$_robot = new $c;
+        }
+        return self::$_robot;
+    }
+    public function robot_prompt_configuration() {
+        $operate = utils::_get('operate');
+        $operate = strtolower($operate);
+
+        if (empty($operate)) {
+           //查询所有配置信息 目前只有一个表一个数据
+            $configuration = common::excuteObjectSql("select id, character_name,professional_field,main_tasks,table_name,table_description,
+                table_structure_configuration,response_rule_configuration,output_format_configuration,fixed_problem_configuration
+            from public.kln_robot_prompt_configuration where id = 1");
+
+            $PromptAndVue = $this->dealPromptFormatAndVue($configuration);
+            //tableDat-VUE 
+            $tableData = $PromptAndVue["vuedata"]["tableData"];
+            //stepData -VUE
+            $stepData = $PromptAndVue["vuedata"]["stepData"]; 
+            //formatList -VUE
+            $formatListType  = $PromptAndVue["vuedata"]["formatListType"];
+            $formatList = $PromptAndVue["vuedata"]["formatList"];
+            //promptFormat
+            $promptFormat =$PromptAndVue["promptFormat"];
+
+            //获取历史变更记录
+            $old_configuration = $this->getChangedLog($configuration["id"]);
+
+            $id = $configuration['id'];
+            $character_name = $configuration['character_name'];
+            $professional_field = $configuration['professional_field'];
+            $main_tasks =  $configuration['main_tasks'];
+            $table_name = $configuration['table_name'];
+            $table_description = $configuration['table_description'];
+
+            $prompt_summary = array("您是专門从事".$professional_field."的".$character_name."...",
+                "表名:{".$table_name."}...",
+                "响应规则,请按以下步骤处理...");
+
+            $data = array(
+                "id"=>$id,
+                "character_name"=>$character_name,
+                "professional_field"=>$professional_field,
+                "main_tasks"=>$main_tasks,
+                "table_name"=>$table_name,
+                "table_description"=>$table_description,
+                "tableData"=>$tableData,
+                "stepData"=>$stepData,
+                "formatList"=>$formatList,
+                "formatListType"=>$formatListType,
+                "complete_prompt"=>$promptFormat,
+                "prompt_summary"=>$prompt_summary,
+                "prompt_log_record"=>$old_configuration
+            );
+            $data = utils::arrayRemoveNull($data);
+            common::echo_json_encode(200,$data);                
+            exit(); 
+        }
+        if ($operate == "save") {
+            $id =common::check_input($_POST['id']);
+            $character_name = common::check_input($_POST['role_name']);
+            $professional_field = common::check_input($_POST['professional_field']);
+            $main_tasks = common::check_input($_POST['main_tasks']);
+            $table_name = common::check_input($_POST['table_name']);
+            $table_description = common::check_input($_POST['table_description']);
+            $outputvalue = common::check_input($_POST['outputvalue']);
+
+            $tableDataList = $_POST['tableDataList'];
+            $stepData = $_POST['stepData'];
+            $formatList = $_POST['formatList'];
+
+
+            $table_structure_configuration = common::check_input(json_encode($tableDataList));
+            $response_rule_configuration = common::check_input(json_encode($stepData));
+
+            $output_data = array("output_type"=>$outputvalue,"data"=>$formatList);
+            $output_format_configuration = common::check_input(json_encode($output_data));
+
+            if(empty($id)){
+                $sql = "INSERT INTO public.kln_robot_prompt_configuration(
+                        character_name, professional_field, main_tasks, table_name, 
+                        table_description, table_structure_configuration, response_rule_configuration, 
+                        output_format_configuration, created_by, created_time)
+                VALUES ('$character_name', '$professional_field', '$main_tasks', '$table_name', 
+                        '$table_description', '$table_structure_configuration', '$response_rule_configuration', 
+                        '$output_format_configuration', '"._getLoginName()."', now());";
+            }else{
+                $sql = "update public.kln_robot_prompt_configuration 
+                    set character_name = '$character_name',professional_field ='$professional_field', main_tasks = '$main_tasks',
+                        table_name = '$table_name',table_description = '$table_description',
+                        table_structure_configuration = '$table_structure_configuration',
+                        response_rule_configuration = '$response_rule_configuration',
+                        output_format_configuration = '$output_format_configuration'
+                where id = '$id';";  
+
+                //插入变更日志记录
+                $sql .= "INSERT INTO public.kln_robot_prompt_configuration_log(ref_id, character_name, professional_field, main_tasks, table_name, 
+                        table_description, table_structure_configuration, response_rule_configuration, 
+                        output_format_configuration, created_by, created_time)
+                VALUES ('$id','$character_name', '$professional_field', '$main_tasks', '$table_name', 
+                        '$table_description', '$table_structure_configuration', '$response_rule_configuration', 
+                        '$output_format_configuration', '"._getLoginName()."', now());";
+
+            }
+            error_log($sql);
+            $rs = common::excuteUpdateSql($sql);
+            if (!$rs) {
+                $data = array("msg" => "save Error");
+            } else {
+                $data = array("msg" => "save Successful");
+            }
+            $data = array("msg" => "save Successful");
+            common::echo_json_encode(200,$data);
+            exit();
+        }
+
+        if($operate == "preview_propmpt_witout_save"){
+            $character_name = common::check_input($_POST['role_name']);
+            $professional_field = common::check_input($_POST['professional_field']);
+            $main_tasks = common::check_input($_POST['main_tasks']);
+            $table_name = common::check_input($_POST['table_name']);
+            $table_description = common::check_input($_POST['table_description']);
+            $outputvalue = common::check_input($_POST['outputvalue']);
+
+            $tableDataList = $_POST['tableDataList'];
+            $stepData = $_POST['stepData'];
+            $formatList = $_POST['formatList'];
+            $table_structure_configuration = common::check_input(json_encode($tableDataList));
+            $response_rule_configuration = common::check_input(json_encode($stepData));
+            $output_data = array("output_type"=>$outputvalue,"data"=>$formatList);
+            $output_format_configuration = common::check_input(json_encode($output_data));
+
+            //组合拼接需要的数据
+            $configuration = array("character_name"=>$character_name,
+                "professional_field"=>$professional_field,
+                "main_tasks"=>$main_tasks,
+                "table_name"=>$table_name,
+                "table_description"=>$table_description,
+                "professional_field"=>$professional_field,
+                "table_structure_configuration"=>$table_structure_configuration,
+                "response_rule_configuration" =>$response_rule_configuration,
+                "output_format_configuration" =>$output_format_configuration
+             );
+            $PromptAndVue = $this->dealPromptFormatAndVue($configuration);
+            //promptFormat
+            $promptFormat =$PromptAndVue["promptFormat"];
+            $character_name = empty($configuration['character_name']) ? "" :$configuration['character_name'];
+            $professional_field = empty($configuration['professional_field']) ? "" :$configuration['professional_field'];
+            $main_tasks =  empty($configuration['main_tasks']) ? "" :$configuration['main_tasks'];
+            $table_name = empty($configuration['table_name']) ? "" :$configuration['table_name'];
+            $table_description = empty($configuration['table_description']) ? "" :$configuration['table_description'];
+            $prompt_summary = array("您是专門从事".$professional_field."的".$character_name."...",
+                "表名:{".$table_name."}...",
+                "响应规则,请按以下步骤处理...");
+
+            $data = array(
+                "complete_prompt"=>$promptFormat,
+                "prompt_summary"=>$prompt_summary
+            );
+            common::echo_json_encode(200,$data);                
+            exit();
+        }
+
+        if($operate == "test_with_ds_claude"){
+            
+            $request_time = date("Y-m-d H:i:s");
+            $ai_method = $_POST["test_ai_method"];
+            $systemPrompt = $_POST["prompt"];
+            $message = $_POST["test_question"];
+            $model = $ai_method == 'DS' ? "deepseek" : "claude";
+
+            $item_value = common::excuteOneSql("select item_value from public.config where item = 'AIAPISetting'");
+            $config = json_decode($item_value,true);
+            $response = AIClientFactory::create($model, $config[$model], $systemPrompt, $message, $history = []);
+            $response_time = date("Y-m-d H:i:s");
+
+            $date1 = new DateTime($request_time);
+            $date2 = new DateTime($response_time);
+            $response_duration = $date2->getTimestamp() - $date1->getTimestamp();
+            $input_token = "";
+            $output_token ="";
+
+            //记录AI API log
+            $sequence = common::excuteOneSql("select count(*) from kln_robot_ai_api_log where request_time >= CURRENT_DATE");
+            $sequence = empty($sequence)? "1" : $sequence;
+            $sequence = sprintf("%05d", $sequence); 
+
+            $question_id = "Q"."".date("YYYYMMDD")."0001"; 
+            common::aiApiLogRecord($sequence,$question_id,$model,$message,$input_token,$response,
+                $output_token,$request_time,$response_time,$response_duration);
+
+            // $sql ="";
+            // //用户权限
+            // $sqlWhere = ' and  ' . common::searchExtendHand_KLN("ocean", $_SESSION["ONLINE_USER"]);
+            // $sql .= $sqlWhere;
+            // $rs = common::excuteListSql($sql);
+
+            $rs = $response;
+            common::echo_json_encode(200,$rs);            
+            exit(); 
+        }
+    }
+
+    public function dealPromptFormatAndVue($configuration){
+        //tableDat-VUE 
+        $tableData = array();
+        $table_structure_text="[";
+        $table_structure_configuration = json_decode($configuration['table_structure_configuration'],true);
+        foreach($table_structure_configuration as $tk =>$tv){
+            $tableData[] = $tv;
+
+            $table_structure_text .='{  
+                "name": "'.$tv["name"].'",  
+                "type": "'.$tv["type"].'",  
+                "description": "'.$tv["description"].'", 
+                "exampledata": "'.$tv["exampledata"].'", 
+            }';
+            if(count($table_structure_configuration)-1 > $tk){
+                $table_structure_text .=",";
+            }
+            $table_structure_text .=common::splicedLlineBreaks();
+        }
+        $table_structure_text.="]";
+
+        //stepData -VUE
+        $stepData = array(); 
+        $response_rule_text = ""; 
+        $response_rule_configuration = json_decode($configuration['response_rule_configuration'],true);
+        foreach($response_rule_configuration as $rk =>$rv){
+            $tempTable = array();
+            $tempTable["description"] = $rv["description"];
+            $stepData[] = $tempTable;
+
+            $response_rule_text .=($rk+1).'.'.$rv["description"];
+            $response_rule_text .=common::splicedLlineBreaks();
+        }
+
+        //formatList -VUE
+        $output_format_text = "{"; 
+        $output_format_configuration = json_decode($configuration['output_format_configuration'],true);
+        $formatListType = $output_format_configuration['output_type'];
+        $formatList = empty($output_format_configuration['data']) ? array(): $output_format_configuration['data'];
+        foreach($formatList as $ok =>$ov){
+            $output_format_text .="\"".$ov['name']."\"".": "."\"".$ov['describe']."\"";
+            $output_format_text .=common::splicedLlineBreaks();
+        }
+        $output_format_text .= "}"; 
+
+        $promptFormat = $this->getCompletePromptFormat();
+        $promptFormat = str_replace('<{professional_field}>', $configuration['character_name'], $promptFormat);
+        $promptFormat = str_replace('<{character_name}>', $configuration['character_name'], $promptFormat);
+        $promptFormat = str_replace('<{main_tasks}>', $configuration['main_tasks'], $promptFormat);
+        $promptFormat = str_replace('<{table}>', $configuration['table_name'], $promptFormat);
+        $promptFormat = str_replace('<{table_structure_configuration}>', $table_structure_text, $promptFormat);
+        $promptFormat = str_replace('<{response_rule_configuration}>', $response_rule_text, $promptFormat);
+        $promptFormat = str_replace('<{number}>', count($response_rule_configuration)+1, $promptFormat);
+        $promptFormat = str_replace('<{output_type}>', $formatListType, $promptFormat);
+        $promptFormat = str_replace('<{output_format_configuration}>', $output_format_text, $promptFormat);
+
+        return array("vuedata"=>array("tableData"=>$tableData,"stepData"=>$stepData,"formatList"=>$formatList,"formatListType"=>$formatListType),
+            "promptFormat" =>$promptFormat);
+    }
+
+    public function getChangedLog($id){
+        $changeLogList = array();
+        $configurationArr = common::excuteListSql("select id, character_name,professional_field,main_tasks,table_name,table_description,
+             created_by,TO_CHAR(created_time, 'YYYY-mm-dd HH24:MI:SS') as created_time,
+            table_structure_configuration,response_rule_configuration,output_format_configuration,fixed_problem_configuration
+        from public.kln_robot_prompt_configuration_log where  ref_id = '$id' order by id desc");
+
+        foreach($configurationArr as $ca){
+            $data = $this->dealPromptFormatAndVue($ca);
+            $temp =array();
+            $temp["time"] = $ca['created_time']." Prompt";
+            $temp["person"] ="提交人:".$ca['created_by'];
+            $temp["text"] = $data['promptFormat'];
+
+            $changeLogList[] = $temp;
+        }
+
+        return $changeLogList;
+    }
+
+    public function getCompletePromptFormat() {
+        $formatTpl = "
+您是专门从<{professional_field}>的 <{character_name}>,请始终以<{output_type}>格式响应。您的主要任务是<{main_tasks}>
+
+表名:<{table}>  
+表结构:  \"columns\": <{table_structure_configuration}>
+
+ 
+    响应规则,请按以下步骤处理:  
+    <{response_rule_configuration}>  
+    <{number}>. 请用以下<{output_type}>格式回复:     
+    <{output_format_configuration}>";
+        return $formatTpl;
+    }
+}
+
+?>

+ 6 - 3
service/tools.class.php

@@ -225,7 +225,7 @@ class tools {
             } else{
                 $data = array("msg" => "Update Successful");
                 //返回addedRules 全部列表
-                $subscribe_rule_sql = "select * from public.notifications_rules where notifications_type = 'Subscribe' and lower(user_login) = '".strtolower(_getLoginName())."' order by id";
+                $subscribe_rule_sql = "select * from public.notifications_rules where notifications_type = 'Subscribe' and lower(user_login) = '".strtolower(_getLoginName())."' order by id desc";
                 $subscribe_rules = common::excuteListSql($subscribe_rule_sql);
                 //整合拼接addedRules
                 $addedRules = array();
@@ -721,7 +721,10 @@ class tools {
 
         if ($operate == "check_notifications_message"){
             $checkUnread = "select id
-                from public.kln_notifiation_info ni  
+                from public.kln_notifiation_info ni 
+                    inner join LATERAL (select oo.h_bol,oo.transport_mode,oo.order_from,oo.m_bol 
+                                from public.kln_ocean oo 
+                                where oo.serial_no = ni.serial_no limit 1) ccc on true 
                     where lower(ni.user_login) in ('".strtolower(_getLoginName())."','all_user')
                         and (ni.frequency_type = 'Instant' 
                             or (ni.frequency_type = 'Daily'  
@@ -1390,7 +1393,7 @@ class tools {
 
                     ccc.order_from,ccc.h_bol,ccc.transport_mode,ccc.m_bol
                 from public.kln_notifiation_info ni
-                        left join LATERAL (select oo.h_bol,oo.transport_mode,oo.order_from,oo.m_bol 
+                        inner join LATERAL (select oo.h_bol,oo.transport_mode,oo.order_from,oo.m_bol 
                             from public.kln_ocean oo 
                             where oo.serial_no = ni.serial_no limit 1) ccc on true
                 where lower(ni.user_login) in ('".strtolower(_getLoginName())."','all_user')

+ 30 - 0
utils/common.class.php

@@ -145,6 +145,7 @@ class common {
                             && !(stripos($action, "feature_update") === 0)
                             && !(stripos($action, "ajax") === 0)
                             && !(stripos($action, "opreation_log") === 0)
+                            && !(stripos($action, "robot") === 0)
                             && !(stripos($action, "system_setting") === 0)
                             && !(stripos($action, "monitoring_setting") === 0)
                             && !(stripos($action, "notifications_rules") === 0)) {
@@ -2482,5 +2483,34 @@ class common {
         }
         return  null;
     }
+
+    //拼接换行
+    public static function splicedLlineBreaks() {
+       return "
+       ";
+    }
+
+    /**
+     * 
+    */
+    public static function aiApiLogRecord($sequence,$question_id,$ai_model,$request_content,$input_token,$ai_response_content,
+        $output_token,$request_time,$response_time,$response_duration) {
+
+        $name = $ai_model =="" ? "DS" : "CD";   
+        $request_id = "R".$name."".date("YYYYMMDD")."".$sequence;    
+        $sql = "INSERT INTO public.kln_robot_ai_api_log(
+                request_id, question_id, ai_model, request_content, input_token, 
+                    ai_response_content, output_token, request_time, response_time, 
+                    response_duration)
+            VALUES ('$request_id', '$question_id', '$ai_model', '$request_content', '$input_token',
+                    '$ai_response_content', '$output_token', '$request_time', '$response_time', '$response_duration');";
+        $rs = common::excuteUpdateSql($sql);
+        if (!$rs) {
+            $data = array("msg" => "save Error");
+            $data = array("msg" => "save Successful");
+            common::echo_json_encode(200,$data);
+            exit();
+        } 
+    }
 }
 ?>

+ 14 - 0
utils/utils.class.php

@@ -865,5 +865,19 @@ class utils {
         }
         return $orderedData;
     }
+
+    /**
+     * 数组去掉null 
+     */
+    public static function arrayRemoveNull($array){
+        foreach ($array as &$value) {
+            if (is_null($value)) {
+                $value = '';
+            }
+        }
+        unset($value); // 断开 $value 的引用
+
+        return $array;
+    }
 }
 ?>