顶顶通-FreeSWITCH二次开发接口

顶顶通-FreeSWITCH二次开发接口

使用easyswoole 框架开发的 新一代电话机器人开源PHP源码

项目地址:https://gitee.com/ddrjcode/robotphp

  • 代理商页面演示地址

http://119.23.229.15:8080

用户名:c0508

密码:123456

包含 AI外呼管理,话术管理,CRM管理,坐席管理等功能。

  • 管理员后台演示地址

http://119.23.229.15

用户名:admin

密码:123456

包含  线路管理,代理商管理等功能

AI外呼管理截图

新一代电话机器人开源PHP源代码-LMLPHP

话术管理截图

新一代电话机器人开源PHP源代码-LMLPHP

坐席页面

新一代电话机器人开源PHP源代码-LMLPHP管理员页面

新一代电话机器人开源PHP源代码-LMLPHP线路管理

新一代电话机器人开源PHP源代码-LMLPHP

机器人话术代码:

<?php
/**
 * Created by PhpStorm.
 * User: WIN10
 * Date: 2021/12/18
 * Time: 16:04
 */
namespace App\Traits;
use App\Model\Speech\SpeechLabelSynonym;
use App\Model\Speech\SpeechNodeModel;
use App\Model\Speech\SpeechProcessModel;
use App\Model\Speech\SpeechProcessNodeSettingModel;
use App\Model\SpeechMul\SpeechMulLabelSynonym;
use App\Model\SpeechMul\SpeechMulProcessSettingModel;

trait SpeechExamineTrait{


    //主流程匹配关键词结果数组
    public function getResultSynonym($speechId)
    {
        $resultSynonym      = [];
        $synonymList        = SpeechLabelSynonym::create()->getAll(["speech_id"=>$speechId]);
        foreach ($synonymList as $val){
            if(isset($val["sls_name"])) {
                $resultSynonym[$val["node_id"]][$val["sls_keyword"]][] = $val["sls_name"];
            }
        }
        return $resultSynonym;
    }


    //获取主流程的$nodesInfo信息 节点信息
    //$processQueuesReal      = []; //真实存在的主流程节点(只有节点才存在到这个主流程)
    public function getNodesInfoList($where)
    {
        $nodesInfo              = [];//所有节点信息map=>(k,v)
        $processNodes           = [];
        $processQueuesReal      = []; //真实存在的主流程节点(只有节点才存在到这个主流程)
        //所有节点的信息
        $nodesInfoList          = SpeechNodeModel::create()->getAll($where);
        foreach ($nodesInfoList as $kk=>$vv)
        {
            $nodesInfo[$vv["node_id"]] = $vv;
            if(!isset($processNodes[$vv["process_id"]])){//真实存在
                array_push($processQueuesReal,$vv["process_id"]);
            }else{
                $processNodes[$vv["process_id"]]         = [];
            }
        }
        return [$nodesInfo,$processQueuesReal];
    }


    //$processNodesArr 所有节点的数组
    //$processQueues  所有的流程按照顺序
    public function getProcessQueues($where)
    {
        $processNodesArr        = [];
        $processQueues          = [];//所有的流程按照顺序
        $processArray           = SpeechProcessModel::create()->getAll($where,'process_id',["sort,process_id","ASC"]);
        foreach ($processArray as $a=>$item){
            array_push($processQueues,$item["process_id"]);
            $processNodesArr[$item["process_id"]] = [];
        }
        return [$processNodesArr,$processQueues];
    }


    //所有的参数节点流程
    public function getArgArray($where)
    {
        $argList  = SpeechProcessNodeSettingModel::create()->getAll($where,"set_key,set_value,node_id");//所有的参数节点流程
        $argArray = [];
        foreach ($argList as $argK=>$argValue){
            $argArray[$argValue["node_id"]][$argValue["set_key"]] = $argValue["set_value"];
        }
        return $argArray;
    }


    //获取所有树的第一个节点集
    // $nodes = SpeechNodeTreeModel::create()->getAll($where,'process_id,node_id,parent_id,nodes_id',["node_id","ASC"]);
    public function getTreeFirstNode($nodes)
    {
        $treeFirstNode      = [];
        foreach ($nodes as $key=>$value)
        {
            if($value["parent_id"]==0){
                $treeFirstNode[$value["process_id"]] = $value;
            }
        }
        return $treeFirstNode;
    }

    public function getMulTreeFirstNode($nodes)
    {
        $treeFirstNode      = [];
        foreach ($nodes as $key=>$value)
        {
            if($value["parent_id"]==0){
                $treeFirstNode[$value["process_mul_id"]] = $value;
            }
        }
        return $treeFirstNode;
    }


    //获取流程的节点的集
    //$processNodesNode 子集
    // $nodes = SpeechNodeTreeModel::create()->getAll($where,'process_id,node_id,parent_id,nodes_id',["node_id","ASC"]);
    //$resultSynonym  主流程匹配关键词结果数组集
    //$childParent 父子节点数组        $childParent            = SpeechSmallNodeRelationModel::create()->getColumn($where,"node_id","small_node_id");
    //$processReal  真实按照顺序的主流程
    //$processRealFlip  主流程反转主流程
    //$treeFirstNode   获取所有树的第一个节点集
    //$nodeSynonymList  匹配的关键词
    //$targetLabel
    //$nodesInfo
    public function getProcessNodesNode($nodes,$processNodesArr,$nodesInfo,$resultSynonym,$childParent,$processReal,$targetLabel,$processRealFlip,$treeFirstNode,$nodeSynonymList)
    {
        //判断是否有相同的节点
        $sameNodeList       = [];
        $processNodesNode   = [];
        //用一个权重数组去获取最终值吧(始终取最大的)
        $priorityArray      = [];
        foreach ($nodes as $key=>$value)
        {
            $valueProcessId                                 = $value["process_id"];
            $processNodesArr[$valueProcessId][]             = $value;
            $subFlowModel   = [];
            $valueNodesId   = $value["nodes_id"];
            $valueParentId  = $value["parent_id"];
            $valueNodeId    = $value["node_id"];
            $priority       = "0"; //分支权重
            if($valueNodesId) {
                $word = $targetLabel[$valueNodesId]??"";
                if ($word) {
                    $synonymCode    =  "W." . $word;
                    $yesSynonym     = [];
                    $isMore         = 0;
                    $arrSubFlow     = [];
                    $synonymArray   = [];
                    switch ($word){
                        case "肯定":
                            if(isset($resultSynonym[$childParent[$valueNodesId]]["yes"])) {
                                $yesSynonym = array_values($resultSynonym[$childParent[$valueNodesId]]["yes"]);
                            }
                            $priority = "5";
                            break;
                        case "否定":
                            if(isset($resultSynonym[$childParent[$valueNodesId]]["no"])) {
                                $yesSynonym = array_values($resultSynonym[$childParent[$valueNodesId]]["no"]);
                            }
                            $priority = "10";
                            break;
                        case "拒绝":
                            if(isset($resultSynonym[$childParent[$valueNodesId]]["reject"])) {
                                $yesSynonym = array_values($resultSynonym[$childParent[$valueNodesId]]["reject"]);
                            }
                            $priority = "12";
                            break;
                        case "默认":
                            $priority = "2";
                            $isMore = 1;
                            break;
                    }
                    if($isMore==0) {//不是默认
                        $synonymSystem = $yesSynonym ?: [$synonymCode];
                        foreach ($synonymSystem as $item){
                            $synonymArray[$item] = $word;
                        }
                        $arrSubFlow = [
                            "condition" => [
                                "text" => $synonymSystem
                            ],
                            "priority" => $priority,
                            "description" => $word
                        ];
                    }elseif($isMore==1){//是默认
                        $arrSubFlow = [
                            "condition" => [
                                "text" => ["any"]
                            ],
                            "priority" => $priority,
                            "description" => $word
                        ];
                    }
                    if(!isset($priorityArray[$valueNodeId])) {
                        $priorityArray[$valueNodeId] = $priority;
                    }else{
                        if($priorityArray[$valueNodeId]<$priority){
                            $priorityArray[$valueNodeId] =  $priority;
                        }
                    }
                    if($nodesInfo[$valueNodeId]["info_talk_info"]) { //有信息的
                        if(!isset($sameNodeList[$valueProcessId][$valueParentId][$valueNodeId])) {//是否存在当前流程,当前父id的,节点id
                            //判断是否当前节点参数是否为空
                            $subFlowModel["F" . $valueNodeId]   = $arrSubFlow;
                            if($isMore==0) {//不是默认
                                $nodeSynonymList[$valueNodeId] = $synonymArray;
                            }
                            $sameNodeList[$valueProcessId][$valueParentId][$valueNodeId] = $key+1;
                        }else{
                            if(!isset($processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"])) {
                                $processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"] = [];
                            }
                            if($isMore==0) {//非默认
                                //有text关键词的操作
                                if ($yesSynonym) {
                                    $processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"]  = array_merge($processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"] ,$yesSynonym);
                                }
                                //没有关键词的操作
                                if (!$yesSynonym) {
                                    array_push($processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"], "W." . $word);
                                }
                                $nodeSynonymList[$valueNodeId] = array_merge($nodeSynonymList[$valueNodeId],$synonymArray);
                            }
                            if($isMore==1) {//默认
//                                $processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"]= ["any"];
                                array_push($processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"], "any");
                            }
                            if(!isset($processNodesNode[$valueProcessId][$valueParentId]["F" . $valueNodeId]["description"])) {
                                $processNodesNode[$valueProcessId][$valueParentId]["F" . $valueNodeId]["description"] =  $word;
                            }else{
                                $processNodesNode[$valueProcessId][$valueParentId]["F" . $valueNodeId]["description"] .= "," . $word;
                            }
                            $processNodesNode[$valueProcessId][$valueParentId]["F" . $valueNodeId]["priority"] = $priorityArray[$valueNodeId];
                        }
                    }
                    elseif(!$nodesInfo[$valueNodeId]["info_talk_info"] && $nodesInfo[$valueNodeId]["type_id"]==2){
                        $next           = $nodesInfo[$value["node_id"]]["next"];  //跳转的条件
                        $nextId         = $nodesInfo[$value["node_id"]]["next_id"];//流程id
                        $process_id     = $nodesInfo[$value["node_id"]]["process_id"]; //该流程id
                        [$resReturnData,$returnKey,$resReturn] = $this->checkNextFlow($next,$nextId,$process_id,$processReal,$processRealFlip,$treeFirstNode,$arrSubFlow);//没有信息的就是跳转信息
                        if(!isset($sameNodeList[$valueProcessId][$valueParentId][$returnKey])) {
                            //判断是否当前节点参数是否为空
//                            $subFlowModel["F".$returnKey]                               = $resReturn;
                            if($resReturn){
                                if(!isset($subFlowModel["F" . $returnKey]["condition"]["text"])) {
                                    $subFlowModel["F" . $returnKey]["condition"]["text"] = [];
                                }
                                if($isMore==0) {//非默认
                                    if ($yesSynonym) {
                                        $subFlowModel["F" . $returnKey]["condition"]["text"] = array_merge($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"],$yesSynonym);
                                    }
                                    if (!$yesSynonym ) {
                                        array_push($subFlowModel ["F" . $returnKey]["condition"]["text"], "W." . $word);
                                    }
                                }
                                if($isMore==1) {//默认
//                                    $subFlowModel ["F" . $returnKey]["condition"]["text"]= ["any"];
                                    array_push($subFlowModel ["F" . $returnKey]["condition"]["text"], "any");
                                }
                                $subFlowModel["F" . $returnKey]["priority"] = $priorityArray[$valueNodeId];
                            }
                            $nodeSynonymList[$returnKey]                                = $synonymArray;
                            $sameNodeList[$valueProcessId][$valueParentId][$returnKey]  = $key+1;
                        }else{
                            if(!isset($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"])) {
                                $processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"] = [];
                            }
                            if($isMore==0) {//非默认
                                if ($yesSynonym) {
                                    $processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"] = array_merge($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"],$yesSynonym);
                                    $nodeSynonymList[$returnKey]      = array_merge($nodeSynonymList[$returnKey],$synonymArray);
                                }
                                if (!$yesSynonym ) {
                                    array_push($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"], "W." . $word);
                                    $nodeSynonymList[$returnKey] = array_merge($nodeSynonymList[$returnKey],$synonymArray);
                                }
                            }
                            if($isMore==1) {//默认
//                                $processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"]= ["any"];
                                array_push($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"], "any");
                            }
                            if(isset($processNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["description"])) {
                                $processNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["description"] =  $word;
                            }else{
                                $processNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["description"] .= "," . $word;
                            }
                            $processNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["priority"] = $priorityArray[$valueNodeId];
                        }
                    }
                }
            }
            //是否存在当前的流程的process的id的,父id
            //不存在就是直接把subFlow赋值给他
            if (!isset($processNodesNode[$valueProcessId][$valueParentId])) {
                $processNodesNode[$valueProcessId][$valueParentId] = $subFlowModel;
            } else {
                //存在就是数组连接一起
                $processNodesNode[$valueProcessId][$valueParentId] = array_merge($processNodesNode[$valueProcessId][$valueParentId],$subFlowModel);
            }
        }
        return [$processNodesArr,$processNodesNode,$nodeSynonymList];
    }


    //获取flow流程
    //获取 $nodeSynonymList  匹配的关键词
    //$firstNode
    //第一个主流程节点
    //$version 版本
    //$processReal  真实按照顺序的主流程
    //$processRealFlip  主流程反转主流程
    //$treeFirstNode   获取所有树的第一个节点集
    //$nodeSynonymList  匹配的关键词
    //$targetLabel
    //$nodesInfo
    //$processNodesNode 子集
    public function getFlowList($flow,$processNodesArr,$nodeSynonymList,$version,$nodesInfo,$processNodesNode,$processReal,$processRealFlip,$treeFirstNode,$argArray,$allNodeWavKey,$allSettingsKey,$priority){
        $count                  = 0;
        $firstNode              = "";//第一个节点
        foreach ($processNodesArr as $ke=>$ve){
            foreach ($ve as $kkk=>$vvv){
                $vvvNodeId = $vvv["node_id"];
                if($count==0){
                    $flow["Start"] = [
                        'action'=>'start',
                        'position'=>[
                            "x"=>2489,
                            "y"=>72
                        ],
                        "subflow"=>['F'.$vvvNodeId."_".$version=>new \stdClass()]
                    ];
                }
                $count++;
                $arg = [];
                $arg["action"]          = "cti_play_and_detect_speech";
                if($count==1){
                    $firstNode = $vvvNodeId."_".$version;
                }
                //模式
                $argM       = $argArray[$vvvNodeId]["moshi"]??"1";
                if(isset($allSettingsKey[$vvvNodeId]['interrupt']) && $allSettingsKey[$vvvNodeId]['interrupt']) {
                    $argM = "2";
                }
                $argLuZao   = $argArray[$vvvNodeId]["luzao"]??"";
                $argKaiShi  = $argArray[$vvvNodeId]["kaishi"]??"";
                $argTingZhi = $argArray[$vvvNodeId]["tingzhi"]??"";
                $argDengDai = $argArray[$vvvNodeId]["dengdai"]??"";
                $argZuiDa   = $argArray[$vvvNodeId]["zuida"]??"";
                $argCanShu  = $argArray[$vvvNodeId]["canshu"]??"";
                $argLuYin   = $argArray[$vvvNodeId]["luyin"]??"";
                //挂机不需要这些参数
                if($nodesInfo[$vvvNodeId]['next']!=1) {
                    $arg["filter"] = [
                        "text" => "S",
                        "dtmf" => "none"
                    ];
                    if ($priority == 1) {
                        $arg["kb_priority"] = 0;
                    } elseif ($priority == 2) {
                        $arg["kb_priority"] = 1;
                    }
                    $arg["timeoutplaybacks"] = [];
                    $arg["timeoutrepetition"] = "";
                    $arg["mismatchplaybacks"] = [];
                    $arg["mismatchrepetition"] = "1";
                    $arg["globalflow"] = [
                        "all"
                    ];
                }else{//挂机节点不起用asr
                    $argM = 0;
                }
                $arg["argument"]        = "'$argM' '16' '' '$argLuZao' '' '$argKaiShi' '$argTingZhi' '$argDengDai' '$argZuiDa' '' '$argCanShu' '$argLuYin' '' ''";
                $arg["position"]        = [
                    "x"=>$nodesInfo[$vvvNodeId]["node_x"],
                    "y"=>$nodesInfo[$vvvNodeId]["node_y"]
                ];
                $arg["description"]     = $nodesInfo[$vvvNodeId]["info_title"];
                if(isset($allNodeWavKey[$vvvNodeId]) && $allNodeWavKey[$vvvNodeId]) {
                    $arg["playbacks"] = [$allNodeWavKey[$vvvNodeId]];
                }else{
                    $arg["playbacks"] = [$nodesInfo[$vvvNodeId]["info_talk_info"]];
                }

                $arg["kb"]          = 'C1';
                if(isset($processNodesNode[$vvv["process_id"]][$vvvNodeId])) {
                    $arg["subflow"] = $processNodesNode[$vvv["process_id"]][$vvvNodeId];
                }else{
                    $next           = $nodesInfo[$vvvNodeId]["next"];  //跳转的条件
                    $nextId         = $nodesInfo[$vvvNodeId]["next_id"];//流程id
                    $processId      = $nodesInfo[$vvvNodeId]["process_id"]; //该流程id
                    [$arg["subflow"],$returnKey,$resReturn] = $this->checkNextFlow($next,$nextId,$processId,$processReal,$processRealFlip,$treeFirstNode);
                }
                if($nodesInfo[$vvvNodeId]["info_talk_info"]) {//如果是跳转节点,没有输入声音就是不输入
                    if($count==1){
                        $vvvNodeId .= "_".$version;
                    }
                    $flow["F" . $vvvNodeId] = $arg;
                }
            }
        }
        return [$flow,$nodeSynonymList,$firstNode];
    }

    //生成一个挂机节点
    public function addEndPoints($flow)
    {
        /**
         * 生成一个挂机节点
         */
        $endPointsArray = [
            'action'=>'hangup',
            'position'=>[
                "x"=>67,
                "y"=>33
            ]
        ];
        $flow["F9999999999999999999"]=$endPointsArray;
        return $flow;
    }
    //生成一个等待用户回答节点
    public function addWaitPoints($flow)
    {
        /**
         * 生成一个挂机节点
         */
        $endWaitArray = [
            'action'=>"cti_play_and_detect_speech",
            "argument"=>"'1' '16' '' '' '' '' '' '' '' '' '' '' '' ''",
            "position"=>[
                "x"=>391833,
                "y"=>2372
            ],
            "playbacks"=>[],
            "description"=>"",
            "sourceflowdepth"=>"1",
            "globalflow"=>[
                "all"
            ],
            "kb"         => 'C1',
            "kb_priority"=>2,
            "condition"=> [
            "complete"=> [],
                "text"=> []
            ],
            "timeoutrepetition"=>"",
            "mismatchplaybacks"=> [],
            "subflow"=>[]
        ];
        $flow["F88888888888888888888"]=$endWaitArray;
//        $flow["F66666666666666666666"]=[
//            "action"=> "return",
//            "position"=> [
//                "x"=> 2263,
//                "y"=> 492
//            ]
//        ];
        return $flow;
    }

    //生成一个挂机播放节点
    public function addHangUpPlayContent($flow,$nodeId,$playbacks)
    {
        $hangUpArray = [
            'action'=>"cti_play_and_detect_speech",
            "argument"=>"'0' '16' '' '' '' '' '' '' '' '' '' '' '' ''",
            "position"=>[
                "x"=>391833,
                "y"=>2372
            ],
            "playbacks"=>$playbacks,
            "description"=>"",
            "sourceflowdepth"=>"1",
            "condition"=> [
                "text"=> []
            ],
            "mismatchplaybacks"=> [],
            "subflow"=>[
                "F9999999999999999999"=> [
                    "condition"=>[
                        "complete"=> [
                            "any"
                        ],
                    ],
                ]
            ]
        ];
        $flow["F".$nodeId] = $hangUpArray;
        return $flow;
    }

    //生成一个挂机播放节点
    public function addHangUpPlay($flow)
    {
        $hangUpArray = [
            'action'=>"cti_play_and_detect_speech",
            "argument"=>"'0' '16' '' '' '' '' '' '' '' '' '' '' '' ''",
            "position"=>[
                "x"=>391833,
                "y"=>2372
            ],
            "playbacks"=>[],
            "description"=>"",
            "sourceflowdepth"=>"1",
            "condition"=> [
                "text"=> []
            ],
            "mismatchplaybacks"=> [],
            "subflow"=>[
                "F9999999999999999999"=> [
                "condition"=>[
                    "text"=> [
                        "any"
                        ],
                    ],
                ]
            ]
        ];
        $flow["F5555555555555555555555"] = $hangUpArray;
        return $flow;
    }

    public function addWaitSubPoints(){
        return [
            "F9999999999999999999"=> [
                "condition"=>[
                    "complete"=> [
                        "timeout()"
                    ]
                ],
                "description"=> "静音挂断"
            ],
            "F66666666666666666666"=>[
                "condition"=> [
                    "complete"=> [],
                    "text"=> [
                        "F.+"
                    ]
                ],
                "description"=> "有声音返回"
            ]
        ];
    }




    //生成一个挂机节点
    public function addHangUpPoints()
    {
        $endPointsArray["F9999999999999999999"] = [
            'condition'=>[
                    'complete'=> [
                        "any"
                    ]
            ],
        ];
        return $endPointsArray;
    }


    //跳转到指定主流程
    public function toMainFlow($flowId)
    {
        $arg["F".$flowId]= [
            "condition"=>[
                "complete"=> [],
                    "text"=>[
                    "any"
                ],
                   "description"=>""
                ]
        ];
        return $arg;
    }

    //跳转到指定多伦会话
    public function toMulFlow($flowId)
    {
        $arg["F".$flowId."_".$flowId]= [
            "condition"=>[
                "complete"=> [],
                "text"=>[
                    "any"
                ],
                "description"=>""
            ]
        ];
        return $arg;
    }


    //判断主流程下个流程的节点
    public function  checkNextFlow($next,$nextId,$process_id,$processReal,$processRealFlip,$treeFirstNode,$arrSubFlow=[])
    {
        $array          = [];
        $keyNext        = $processRealFlip[$process_id]+1;//下一个next
        $hangUp         = $arrSubFlow?:["description"=>"无效回答", "condition"=>["text"=>["any"]]];
        $nextProcess    = $arrSubFlow?: ["condition" => ["text" => ["any"]], "description" => "跳转下一个流程"];
        $keyReturn      = "";
        $resReturn      = "";
        switch ($next)
        {
            case 0:
            case 2:
                if(isset($processReal[$keyNext])){
                    $array["F" . $treeFirstNode[$processReal[$keyNext]]["node_id"]] = $nextProcess;
                    $keyReturn   = $treeFirstNode[$processReal[$keyNext]]["node_id"];
                    $resReturn   = $nextProcess;
                }else{
                    $array["F9999999999999999999"] = $hangUp;
                    $keyReturn  = "9999999999999999999";
                    $resReturn   = $hangUp;
                }
                break;
            case 1:
                $array["F9999999999999999999"] = $hangUp;
                $keyReturn  = "9999999999999999999";
                $resReturn   = $hangUp;
                break;
            case 3:
                if(isset($treeFirstNode[$nextId])) {
                    $fistNode = $treeFirstNode[$nextId];
                    $array["F" . $fistNode["node_id"]] = $nextProcess;
                    $keyReturn   = $fistNode["node_id"];
                    $resReturn   = $nextProcess;
                }else{
                    $array["F9999999999999999999"] = $hangUp;
                    $keyReturn       = "9999999999999999999";
                    $resReturn       = $hangUp;
                }
                break;
            case 4://返回接口
                $keyReturn  = substr(microtime(true),2,8).rand(0,99);
                $resReturn= [
                    'action'  =>'return',
                    'position'=>[
                        'x'=>4085,
                        'y'=>377
                    ],
                ];
                $array["F".$keyReturn] = $resReturn;
                break;
            }

        return [$array,$keyReturn,$resReturn];
    }



    //多伦会话匹配关键词结果数组
    public function getMulResultSynonym($speechId)
    {
        $resultSynonym      = [];
        $synonymList        = SpeechMulLabelSynonym::create()->getAll(["speech_id"=>$speechId]);
        foreach ($synonymList as $val){
            if(isset($val["sls_name"])) {
                $resultSynonym[$val["node_mul_id"]][$val["sls_keyword"]][] = $val["sls_name"];
            }
        }
        return $resultSynonym;
    }


    //获取所有子节点
    public function getMulProcessNodesNode($flow,$nodesMul,$resultMulSynonym,$childMulParent,$nodesMulInfo,$targetMulLabel,$nodeSynonymList,$treeFirstNode)
    {
        //判断是否有相同的节点
        $sameNodeList           = [];
        $processMulNodesNode    = [];
        $processMulNodesArr     = [];//所有全局话术的根节点
        //用一个权重数组去获取最终值吧(始终取最大的)
        $priorityArray      = [];
        foreach ($nodesMul as $key=>$value)
        {
            $valueProcessId                     = $value["process_mul_id"];
            $processMulNodesArr[$valueProcessId][]          = $value;
            $subFlowModel   = [];
            $valueNodesId   = $value["nodes_id"];
            $valueParentId  = $value["parent_id"];
            $valueNodeId    = "F".$value["node_mul_id"]."_".$value["node_mul_id"];
            $priority       = "0";
            if($valueNodesId) {
                $word = $targetMulLabel[$valueNodesId]??"";
                if ($word) {
                    $synonymCode    =  "W." . $word;
                    $yesSynonym     = [];
                    $isMore         = 0;
                    $arrSubFlow     = [];
                    $synonymArray   = [];
                    switch ($word){
                        case "肯定":
                            if(isset($resultMulSynonym[$childMulParent[$valueNodesId]]["yes"])) {
                                $yesSynonym = array_values($resultMulSynonym[$childMulParent[$valueNodesId]]["yes"]);
                            }
                            $priority = "5";
                            break;
                        case "否定":
                            if(isset($resultMulSynonym[$childMulParent[$valueNodesId]]["no"])) {
                                $yesSynonym = array_values($resultMulSynonym[$childMulParent[$valueNodesId]]["no"]);
                            }
                            $priority = "10";
                            break;
                        case "拒绝":
                            if(isset($resultMulSynonym[$childMulParent[$valueNodesId]]["reject"])) {
                                $yesSynonym = array_values($resultMulSynonym[$childMulParent[$valueNodesId]]["reject"]);
                            }
                            $priority = "12";
                            break;
                        case "默认":
                            $priority = "2";
                            $isMore = 1;
                            break;
                    }
                    if($isMore==0) {//不是默认
                        $synonymSystem = $yesSynonym ?: [$synonymCode];
                        foreach ($synonymSystem as $item){
                            $synonymArray[$item] = $word;
                        }
                        $arrSubFlow = [
                            "condition" => [
                                "text" => $synonymSystem
                            ],
                            "priority" => $priority,
                            "description" => $word
                        ];
                    }elseif($isMore==1){//是默认
                        $arrSubFlow = [
                            "condition" => [
                                "text" => ["any"]
                            ],
                            "priority" => $priority,
                            "description" => $word
                        ];
                    }
                    if(!isset($priorityArray[$valueNodeId])) {
                        $priorityArray[$valueNodeId] = $priority;
                    }else{
                        if($priorityArray[$valueNodeId]<$priority){
                            $priorityArray[$valueNodeId] =  $priority;
                        }
                    }
                    if($nodesMulInfo[$value["node_mul_id"]]["info_talk_info"]) { //有信息的(多伦会话只要有信息判断)
                        if(!isset($sameNodeList[$valueProcessId][$valueParentId][$valueNodeId])) {//是否存在当前流程,当前父id的,节点id
                            //判断是否当前节点参数是否为空
                            $subFlowModel[$valueNodeId]   = $arrSubFlow;
                            if($isMore==0) {//不是默认
                                $nodeSynonymList[$valueNodeId] = $synonymArray;
                            }
                            $sameNodeList[$valueProcessId][$valueParentId][$valueNodeId] = $key+1;
                        }else{
                            if(!isset($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"])) {
                                $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"] = [];
                            }
                            if($isMore==0) {//非默认
                                if ($yesSynonym) {
                                    $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"]  = array_merge($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"] ,$yesSynonym);
                                }
                                if (!$yesSynonym) {

                                    array_push($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"], "W." . $word);
                                }
                                $nodeSynonymList[$valueNodeId] = array_merge($nodeSynonymList[$valueNodeId],$synonymArray);
                            }
                            if($isMore==1) {//默认
//                                $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"]= ["any"];
                                array_push($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"], "any");
                            }
                            if(!isset($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["description"])) {
                                $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["description"] =  $word;
                            }else{
                                $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["description"] .= "," . $word;
                            }
                            $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["priority"] = $priorityArray[$valueNodeId];
                        }
                    }
                    elseif(!$nodesMulInfo[$value["node_mul_id"]]["info_talk_info"] && $nodesMulInfo[$value["node_mul_id"]]["type_id"]==2){
                        $next           = $nodesMulInfo[$value["node_mul_id"]]["next"];  //跳转的条件
                        $nextId         = $nodesMulInfo[$value["node_mul_id"]]["next_id"];//流程id
                        [$arrSubFlows,$returnKey,$resReturn,$flow] = $this->checkNextMulFlow($next,$nextId,$treeFirstNode,$flow);
                        if(!isset($sameNodeList[$valueProcessId][$valueParentId][$returnKey])) {
                            //判断是否当前节点参数是否为空
                            if($resReturn){
                                if(!isset($subFlowModel["F" . $returnKey]["condition"]["text"])) {
                                    $subFlowModel["F" . $returnKey]["condition"]["text"] = [];
                                }
                                if($isMore==0) {//非默认
                                    if ($yesSynonym) {
                                        $subFlowModel["F" . $returnKey]["condition"]["text"] = array_merge($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"],$yesSynonym);
                                    }
                                    if (!$yesSynonym ) {
                                        array_push($subFlowModel ["F" . $returnKey]["condition"]["text"], "W." . $word);
                                    }
                                }
                                if($isMore==1) {//默认
//                                    $subFlowModel ["F" . $returnKey]["condition"]["text"]= ["any"];
                                    array_push($subFlowModel ["F" . $returnKey]["condition"]["text"], "any");
                                }
                                $subFlowModel["F" . $returnKey]["priority"] = $priorityArray[$valueNodeId];
                            }
                            if($isMore==0) {//不是默认
                                $nodeSynonymList[$valueNodeId] = $synonymArray;
                            }
//                            $subFlowModel["F".$returnKey]                               = $resReturn;
                            $sameNodeList[$valueProcessId][$valueParentId][$returnKey]  = $key+1;
                        }else{
                            if(!isset($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"])) {
                                $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"] = [];
                            }
                            if($isMore==0) {//非默认
                                if ($yesSynonym) {
                                    $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"] = array_merge($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"],$yesSynonym);
                                }
                                if (!$yesSynonym ) {
                                    array_push($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"], "W." . $word);
                                }
                                $nodeSynonymList[$valueNodeId] = array_merge($nodeSynonymList[$valueNodeId],$synonymArray);
                            }
                            if($isMore==1) {//默认
//                                $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"]= ["any"];
                                array_push($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"], "any");
                            }
                            if(!isset($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["description"])){
                                $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["description"] = ",".$word;
                            }else{
                                $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["description"] .= ",".$word;
                            }
                            $processMulNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["priority"] = $priorityArray[$valueNodeId];
                        }
                    }
                }
            }
            if (!isset($processMulNodesNode[$valueProcessId][$valueParentId])) {
                $processMulNodesNode[$valueProcessId][$valueParentId] = $subFlowModel;
            } else {
                $processMulNodesNode[$valueProcessId][$valueParentId] = array_merge($processMulNodesNode[$valueProcessId][$valueParentId],$subFlowModel);
            }
        }
        return [$processMulNodesNode,$nodeSynonymList,$processMulNodesArr,$flow];
    }

    //获取所有的
    public function getMulFlowList($flow,$processMulNodesArr,$argMulArray,$nodesMulInfo,$treeFirstNode,$processMulNodesNode,$allNodeMulWavKey,$priority)
    {
        $count                  = 0;
        foreach ($processMulNodesArr as $ke=>$ve){
            foreach ($ve as $kkk=>$vvv){
                $vvvNodeId = $vvv["node_mul_id"];
                $count++;
                $arg = [];
                $arg["action"]          = "cti_play_and_detect_speech";
                //模式
                $argM       = $argMulArray[$vvvNodeId]["moshi"]??"1";
                $argLuZao   = $argMulArray[$vvvNodeId]["luzao"]??"";
                $argKaiShi  = $argMulArray[$vvvNodeId]["kaishi"]??"";
                $argTingZhi = $argMulArray[$vvvNodeId]["tingzhi"]??"";
                $argDengDai = $argMulArray[$vvvNodeId]["dengdai"]??"";
                $argZuiDa   = $argMulArray[$vvvNodeId]["zuida"]??"";
                $argCanShu  = $argMulArray[$vvvNodeId]["canshu"]??"";
                $argLuYin   = $argMulArray[$vvvNodeId]["luyin"]??"";
                //挂机不需要这些参数
                if($nodesMulInfo[$vvvNodeId]['next']!=1) {
                    $arg["filter"] = [
                        "text" => "S",
                        "dtmf" => "none"
                    ];
                    if ($priority == 1) {
                        $arg["kb_priority"] = 0;
                    } elseif ($priority == 2) {
                        $arg["kb_priority"] = 1;
                    }
                    $arg["timeoutplaybacks"] = [];
                    $arg["timeoutrepetition"] = "";
                    $arg["mismatchplaybacks"] = [];
                    $arg["mismatchrepetition"] = "1";
                    $arg["kb"] = 'C1';
                    $arg["globalflow"] = [
                        "all"
                    ];
                }else{//挂机节点不起用asr
                    $argM = 0;
                }
                $arg["argument"]        = "'$argM' '16' '' '$argLuZao' '' '$argKaiShi' '$argTingZhi' '$argDengDai' '$argZuiDa' '' '$argCanShu' '$argLuYin' '' ''";
                $arg["position"]        = [
                    "x"=>$nodesMulInfo[$vvvNodeId]["node_x"],
                    "y"=>$nodesMulInfo[$vvvNodeId]["node_y"]];
                $arg["description"]     = $nodesMulInfo[$vvvNodeId]["info_title"];
                if(isset($allNodeMulWavKey[$vvvNodeId]) && $allNodeMulWavKey[$vvvNodeId]) {
                    $arg["playbacks"] = [$allNodeMulWavKey[$vvvNodeId]];
                }else{
                    $arg["playbacks"] = [$nodesMulInfo[$vvvNodeId]["info_talk_info"]];
                }

                if(isset($processMulNodesNode[$vvv["process_mul_id"]][$vvvNodeId])) {
                    $arg["subflow"] = $processMulNodesNode[$vvv["process_mul_id"]][$vvvNodeId];
                }else{
                    $next           = $nodesMulInfo[$vvvNodeId]["next"];   //跳转的条件
                    $nextId         = $nodesMulInfo[$vvvNodeId]["next_id"];//流程id
                    [$arg["subflow"],$returnKey,$resReturn,$flow] = $this->checkNextMulFlow($next,$nextId,$treeFirstNode,$flow);
                }
                if($nodesMulInfo[$vvvNodeId]["info_talk_info"]) {//如果是跳转节点,没有输入声音就是不输入
                    $keyNode = "F".$vvvNodeId."_".$vvvNodeId;
                    $flow[$keyNode] = $arg;
                }
            }
        }
        return $flow;
    }

    //多伦会话下一步
    public function checkNextMulFlow($next,$nextId,$treeFirstNode,$flow)
    {
        $array          = [];
        $info           = ["description"=>"默认回答", "condition"=>["text"=>["any"]]];
        $keyReturn      = "";
        $resReturn      = "";
        switch ($next)
        {
            case 0://普通节点默认挂机
            case 1://挂机
                $hangK              = substr(microtime(true),2,8).rand(0,99);
                $hangKey            = "F".$hangK;
                $array[$hangKey]    = $info;
                $keyReturn          = $hangK;
                $resReturn          = $info;
                //挂机节点需要添加挂机节点
                /**
                 * 生成一个挂机节点
                 */
                $endPointsArray = [
                    'action'=>'hangup',
                    'position'=>[
                        "x"=>67,
                        "y"=>33
                    ]
                ];
                $flow[$hangKey]=$endPointsArray;
                break;
            case 2://跳转指定多伦会话
                $hangKey            = "F".$nextId."_".$nextId;
                $array[$hangKey]    = $info;
                $keyReturn          = $nextId."_".$nextId;
                $resReturn          = $info;
                break;
            case 3://指定主流程
                $hangKey            = "F".$treeFirstNode[$nextId]['node_id'];
                $array[$hangKey]    = $info;
                $keyReturn          = $treeFirstNode[$nextId]['node_id'];
                $resReturn          = $info;
                break;
        }
        return [$array,$keyReturn,$resReturn,$flow];
    }


    //所有的多伦会话节点流程
    public function getMulArgArray($where)
    {
        $argList  = SpeechMulProcessSettingModel::create()->getAll($where,"set_key,set_value,node_mul_id");//所有的参数节点流程
        $argArray = [];
        foreach ($argList as $argK=>$argValue){
            $argArray[$argValue["node_mul_id"]][$argValue["set_key"]] = $argValue["set_value"];
        }
        return $argArray;
    }



}
03-03 08:42