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


    使用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外呼管理截图

    话术管理截图

    坐席页面

    管理员页面

    线路管理

    机器人话术代码:

    1. /**
    2. * Created by PhpStorm.
    3. * User: WIN10
    4. * Date: 2021/12/18
    5. * Time: 16:04
    6. */
    7. namespace App\Traits;
    8. use App\Model\Speech\SpeechLabelSynonym;
    9. use App\Model\Speech\SpeechNodeModel;
    10. use App\Model\Speech\SpeechProcessModel;
    11. use App\Model\Speech\SpeechProcessNodeSettingModel;
    12. use App\Model\SpeechMul\SpeechMulLabelSynonym;
    13. use App\Model\SpeechMul\SpeechMulProcessSettingModel;
    14. trait SpeechExamineTrait{
    15. //主流程匹配关键词结果数组
    16. public function getResultSynonym($speechId)
    17. {
    18. $resultSynonym = [];
    19. $synonymList = SpeechLabelSynonym::create()->getAll(["speech_id"=>$speechId]);
    20. foreach ($synonymList as $val){
    21. if(isset($val["sls_name"])) {
    22. $resultSynonym[$val["node_id"]][$val["sls_keyword"]][] = $val["sls_name"];
    23. }
    24. }
    25. return $resultSynonym;
    26. }
    27. //获取主流程的$nodesInfo信息 节点信息
    28. //$processQueuesReal = []; //真实存在的主流程节点(只有节点才存在到这个主流程)
    29. public function getNodesInfoList($where)
    30. {
    31. $nodesInfo = [];//所有节点信息map=>(k,v)
    32. $processNodes = [];
    33. $processQueuesReal = []; //真实存在的主流程节点(只有节点才存在到这个主流程)
    34. //所有节点的信息
    35. $nodesInfoList = SpeechNodeModel::create()->getAll($where);
    36. foreach ($nodesInfoList as $kk=>$vv)
    37. {
    38. $nodesInfo[$vv["node_id"]] = $vv;
    39. if(!isset($processNodes[$vv["process_id"]])){//真实存在
    40. array_push($processQueuesReal,$vv["process_id"]);
    41. }else{
    42. $processNodes[$vv["process_id"]] = [];
    43. }
    44. }
    45. return [$nodesInfo,$processQueuesReal];
    46. }
    47. //$processNodesArr 所有节点的数组
    48. //$processQueues 所有的流程按照顺序
    49. public function getProcessQueues($where)
    50. {
    51. $processNodesArr = [];
    52. $processQueues = [];//所有的流程按照顺序
    53. $processArray = SpeechProcessModel::create()->getAll($where,'process_id',["sort,process_id","ASC"]);
    54. foreach ($processArray as $a=>$item){
    55. array_push($processQueues,$item["process_id"]);
    56. $processNodesArr[$item["process_id"]] = [];
    57. }
    58. return [$processNodesArr,$processQueues];
    59. }
    60. //所有的参数节点流程
    61. public function getArgArray($where)
    62. {
    63. $argList = SpeechProcessNodeSettingModel::create()->getAll($where,"set_key,set_value,node_id");//所有的参数节点流程
    64. $argArray = [];
    65. foreach ($argList as $argK=>$argValue){
    66. $argArray[$argValue["node_id"]][$argValue["set_key"]] = $argValue["set_value"];
    67. }
    68. return $argArray;
    69. }
    70. //获取所有树的第一个节点集
    71. // $nodes = SpeechNodeTreeModel::create()->getAll($where,'process_id,node_id,parent_id,nodes_id',["node_id","ASC"]);
    72. public function getTreeFirstNode($nodes)
    73. {
    74. $treeFirstNode = [];
    75. foreach ($nodes as $key=>$value)
    76. {
    77. if($value["parent_id"]==0){
    78. $treeFirstNode[$value["process_id"]] = $value;
    79. }
    80. }
    81. return $treeFirstNode;
    82. }
    83. public function getMulTreeFirstNode($nodes)
    84. {
    85. $treeFirstNode = [];
    86. foreach ($nodes as $key=>$value)
    87. {
    88. if($value["parent_id"]==0){
    89. $treeFirstNode[$value["process_mul_id"]] = $value;
    90. }
    91. }
    92. return $treeFirstNode;
    93. }
    94. //获取流程的节点的集
    95. //$processNodesNode 子集
    96. // $nodes = SpeechNodeTreeModel::create()->getAll($where,'process_id,node_id,parent_id,nodes_id',["node_id","ASC"]);
    97. //$resultSynonym 主流程匹配关键词结果数组集
    98. //$childParent 父子节点数组 $childParent = SpeechSmallNodeRelationModel::create()->getColumn($where,"node_id","small_node_id");
    99. //$processReal 真实按照顺序的主流程
    100. //$processRealFlip 主流程反转主流程
    101. //$treeFirstNode 获取所有树的第一个节点集
    102. //$nodeSynonymList 匹配的关键词
    103. //$targetLabel
    104. //$nodesInfo
    105. public function getProcessNodesNode($nodes,$processNodesArr,$nodesInfo,$resultSynonym,$childParent,$processReal,$targetLabel,$processRealFlip,$treeFirstNode,$nodeSynonymList)
    106. {
    107. //判断是否有相同的节点
    108. $sameNodeList = [];
    109. $processNodesNode = [];
    110. //用一个权重数组去获取最终值吧(始终取最大的)
    111. $priorityArray = [];
    112. foreach ($nodes as $key=>$value)
    113. {
    114. $valueProcessId = $value["process_id"];
    115. $processNodesArr[$valueProcessId][] = $value;
    116. $subFlowModel = [];
    117. $valueNodesId = $value["nodes_id"];
    118. $valueParentId = $value["parent_id"];
    119. $valueNodeId = $value["node_id"];
    120. $priority = "0"; //分支权重
    121. if($valueNodesId) {
    122. $word = $targetLabel[$valueNodesId]??"";
    123. if ($word) {
    124. $synonymCode = "W." . $word;
    125. $yesSynonym = [];
    126. $isMore = 0;
    127. $arrSubFlow = [];
    128. $synonymArray = [];
    129. switch ($word){
    130. case "肯定":
    131. if(isset($resultSynonym[$childParent[$valueNodesId]]["yes"])) {
    132. $yesSynonym = array_values($resultSynonym[$childParent[$valueNodesId]]["yes"]);
    133. }
    134. $priority = "5";
    135. break;
    136. case "否定":
    137. if(isset($resultSynonym[$childParent[$valueNodesId]]["no"])) {
    138. $yesSynonym = array_values($resultSynonym[$childParent[$valueNodesId]]["no"]);
    139. }
    140. $priority = "10";
    141. break;
    142. case "拒绝":
    143. if(isset($resultSynonym[$childParent[$valueNodesId]]["reject"])) {
    144. $yesSynonym = array_values($resultSynonym[$childParent[$valueNodesId]]["reject"]);
    145. }
    146. $priority = "12";
    147. break;
    148. case "默认":
    149. $priority = "2";
    150. $isMore = 1;
    151. break;
    152. }
    153. if($isMore==0) {//不是默认
    154. $synonymSystem = $yesSynonym ?: [$synonymCode];
    155. foreach ($synonymSystem as $item){
    156. $synonymArray[$item] = $word;
    157. }
    158. $arrSubFlow = [
    159. "condition" => [
    160. "text" => $synonymSystem
    161. ],
    162. "priority" => $priority,
    163. "description" => $word
    164. ];
    165. }elseif($isMore==1){//是默认
    166. $arrSubFlow = [
    167. "condition" => [
    168. "text" => ["any"]
    169. ],
    170. "priority" => $priority,
    171. "description" => $word
    172. ];
    173. }
    174. if(!isset($priorityArray[$valueNodeId])) {
    175. $priorityArray[$valueNodeId] = $priority;
    176. }else{
    177. if($priorityArray[$valueNodeId]<$priority){
    178. $priorityArray[$valueNodeId] = $priority;
    179. }
    180. }
    181. if($nodesInfo[$valueNodeId]["info_talk_info"]) { //有信息的
    182. if(!isset($sameNodeList[$valueProcessId][$valueParentId][$valueNodeId])) {//是否存在当前流程,当前父id的,节点id
    183. //判断是否当前节点参数是否为空
    184. $subFlowModel["F" . $valueNodeId] = $arrSubFlow;
    185. if($isMore==0) {//不是默认
    186. $nodeSynonymList[$valueNodeId] = $synonymArray;
    187. }
    188. $sameNodeList[$valueProcessId][$valueParentId][$valueNodeId] = $key+1;
    189. }else{
    190. if(!isset($processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"])) {
    191. $processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"] = [];
    192. }
    193. if($isMore==0) {//非默认
    194. //有text关键词的操作
    195. if ($yesSynonym) {
    196. $processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"] = array_merge($processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"] ,$yesSynonym);
    197. }
    198. //没有关键词的操作
    199. if (!$yesSynonym) {
    200. array_push($processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"], "W." . $word);
    201. }
    202. $nodeSynonymList[$valueNodeId] = array_merge($nodeSynonymList[$valueNodeId],$synonymArray);
    203. }
    204. if($isMore==1) {//默认
    205. // $processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"]= ["any"];
    206. array_push($processNodesNode[$valueProcessId][$valueParentId] ["F" . $valueNodeId]["condition"]["text"], "any");
    207. }
    208. if(!isset($processNodesNode[$valueProcessId][$valueParentId]["F" . $valueNodeId]["description"])) {
    209. $processNodesNode[$valueProcessId][$valueParentId]["F" . $valueNodeId]["description"] = $word;
    210. }else{
    211. $processNodesNode[$valueProcessId][$valueParentId]["F" . $valueNodeId]["description"] .= "," . $word;
    212. }
    213. $processNodesNode[$valueProcessId][$valueParentId]["F" . $valueNodeId]["priority"] = $priorityArray[$valueNodeId];
    214. }
    215. }
    216. elseif(!$nodesInfo[$valueNodeId]["info_talk_info"] && $nodesInfo[$valueNodeId]["type_id"]==2){
    217. $next = $nodesInfo[$value["node_id"]]["next"]; //跳转的条件
    218. $nextId = $nodesInfo[$value["node_id"]]["next_id"];//流程id
    219. $process_id = $nodesInfo[$value["node_id"]]["process_id"]; //该流程id
    220. [$resReturnData,$returnKey,$resReturn] = $this->checkNextFlow($next,$nextId,$process_id,$processReal,$processRealFlip,$treeFirstNode,$arrSubFlow);//没有信息的就是跳转信息
    221. if(!isset($sameNodeList[$valueProcessId][$valueParentId][$returnKey])) {
    222. //判断是否当前节点参数是否为空
    223. // $subFlowModel["F".$returnKey] = $resReturn;
    224. if($resReturn){
    225. if(!isset($subFlowModel["F" . $returnKey]["condition"]["text"])) {
    226. $subFlowModel["F" . $returnKey]["condition"]["text"] = [];
    227. }
    228. if($isMore==0) {//非默认
    229. if ($yesSynonym) {
    230. $subFlowModel["F" . $returnKey]["condition"]["text"] = array_merge($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"],$yesSynonym);
    231. }
    232. if (!$yesSynonym ) {
    233. array_push($subFlowModel ["F" . $returnKey]["condition"]["text"], "W." . $word);
    234. }
    235. }
    236. if($isMore==1) {//默认
    237. // $subFlowModel ["F" . $returnKey]["condition"]["text"]= ["any"];
    238. array_push($subFlowModel ["F" . $returnKey]["condition"]["text"], "any");
    239. }
    240. $subFlowModel["F" . $returnKey]["priority"] = $priorityArray[$valueNodeId];
    241. }
    242. $nodeSynonymList[$returnKey] = $synonymArray;
    243. $sameNodeList[$valueProcessId][$valueParentId][$returnKey] = $key+1;
    244. }else{
    245. if(!isset($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"])) {
    246. $processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"] = [];
    247. }
    248. if($isMore==0) {//非默认
    249. if ($yesSynonym) {
    250. $processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"] = array_merge($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"],$yesSynonym);
    251. $nodeSynonymList[$returnKey] = array_merge($nodeSynonymList[$returnKey],$synonymArray);
    252. }
    253. if (!$yesSynonym ) {
    254. array_push($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"], "W." . $word);
    255. $nodeSynonymList[$returnKey] = array_merge($nodeSynonymList[$returnKey],$synonymArray);
    256. }
    257. }
    258. if($isMore==1) {//默认
    259. // $processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"]= ["any"];
    260. array_push($processNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"], "any");
    261. }
    262. if(isset($processNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["description"])) {
    263. $processNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["description"] = $word;
    264. }else{
    265. $processNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["description"] .= "," . $word;
    266. }
    267. $processNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["priority"] = $priorityArray[$valueNodeId];
    268. }
    269. }
    270. }
    271. }
    272. //是否存在当前的流程的process的id的,父id
    273. //不存在就是直接把subFlow赋值给他
    274. if (!isset($processNodesNode[$valueProcessId][$valueParentId])) {
    275. $processNodesNode[$valueProcessId][$valueParentId] = $subFlowModel;
    276. } else {
    277. //存在就是数组连接一起
    278. $processNodesNode[$valueProcessId][$valueParentId] = array_merge($processNodesNode[$valueProcessId][$valueParentId],$subFlowModel);
    279. }
    280. }
    281. return [$processNodesArr,$processNodesNode,$nodeSynonymList];
    282. }
    283. //获取flow流程
    284. //获取 $nodeSynonymList 匹配的关键词
    285. //$firstNode
    286. //第一个主流程节点
    287. //$version 版本
    288. //$processReal 真实按照顺序的主流程
    289. //$processRealFlip 主流程反转主流程
    290. //$treeFirstNode 获取所有树的第一个节点集
    291. //$nodeSynonymList 匹配的关键词
    292. //$targetLabel
    293. //$nodesInfo
    294. //$processNodesNode 子集
    295. public function getFlowList($flow,$processNodesArr,$nodeSynonymList,$version,$nodesInfo,$processNodesNode,$processReal,$processRealFlip,$treeFirstNode,$argArray,$allNodeWavKey,$allSettingsKey,$priority){
    296. $count = 0;
    297. $firstNode = "";//第一个节点
    298. foreach ($processNodesArr as $ke=>$ve){
    299. foreach ($ve as $kkk=>$vvv){
    300. $vvvNodeId = $vvv["node_id"];
    301. if($count==0){
    302. $flow["Start"] = [
    303. 'action'=>'start',
    304. 'position'=>[
    305. "x"=>2489,
    306. "y"=>72
    307. ],
    308. "subflow"=>['F'.$vvvNodeId."_".$version=>new \stdClass()]
    309. ];
    310. }
    311. $count++;
    312. $arg = [];
    313. $arg["action"] = "cti_play_and_detect_speech";
    314. if($count==1){
    315. $firstNode = $vvvNodeId."_".$version;
    316. }
    317. //模式
    318. $argM = $argArray[$vvvNodeId]["moshi"]??"1";
    319. if(isset($allSettingsKey[$vvvNodeId]['interrupt']) && $allSettingsKey[$vvvNodeId]['interrupt']) {
    320. $argM = "2";
    321. }
    322. $argLuZao = $argArray[$vvvNodeId]["luzao"]??"";
    323. $argKaiShi = $argArray[$vvvNodeId]["kaishi"]??"";
    324. $argTingZhi = $argArray[$vvvNodeId]["tingzhi"]??"";
    325. $argDengDai = $argArray[$vvvNodeId]["dengdai"]??"";
    326. $argZuiDa = $argArray[$vvvNodeId]["zuida"]??"";
    327. $argCanShu = $argArray[$vvvNodeId]["canshu"]??"";
    328. $argLuYin = $argArray[$vvvNodeId]["luyin"]??"";
    329. //挂机不需要这些参数
    330. if($nodesInfo[$vvvNodeId]['next']!=1) {
    331. $arg["filter"] = [
    332. "text" => "S",
    333. "dtmf" => "none"
    334. ];
    335. if ($priority == 1) {
    336. $arg["kb_priority"] = 0;
    337. } elseif ($priority == 2) {
    338. $arg["kb_priority"] = 1;
    339. }
    340. $arg["timeoutplaybacks"] = [];
    341. $arg["timeoutrepetition"] = "";
    342. $arg["mismatchplaybacks"] = [];
    343. $arg["mismatchrepetition"] = "1";
    344. $arg["globalflow"] = [
    345. "all"
    346. ];
    347. }else{//挂机节点不起用asr
    348. $argM = 0;
    349. }
    350. $arg["argument"] = "'$argM' '16' '' '$argLuZao' '' '$argKaiShi' '$argTingZhi' '$argDengDai' '$argZuiDa' '' '$argCanShu' '$argLuYin' '' ''";
    351. $arg["position"] = [
    352. "x"=>$nodesInfo[$vvvNodeId]["node_x"],
    353. "y"=>$nodesInfo[$vvvNodeId]["node_y"]
    354. ];
    355. $arg["description"] = $nodesInfo[$vvvNodeId]["info_title"];
    356. if(isset($allNodeWavKey[$vvvNodeId]) && $allNodeWavKey[$vvvNodeId]) {
    357. $arg["playbacks"] = [$allNodeWavKey[$vvvNodeId]];
    358. }else{
    359. $arg["playbacks"] = [$nodesInfo[$vvvNodeId]["info_talk_info"]];
    360. }
    361. $arg["kb"] = 'C1';
    362. if(isset($processNodesNode[$vvv["process_id"]][$vvvNodeId])) {
    363. $arg["subflow"] = $processNodesNode[$vvv["process_id"]][$vvvNodeId];
    364. }else{
    365. $next = $nodesInfo[$vvvNodeId]["next"]; //跳转的条件
    366. $nextId = $nodesInfo[$vvvNodeId]["next_id"];//流程id
    367. $processId = $nodesInfo[$vvvNodeId]["process_id"]; //该流程id
    368. [$arg["subflow"],$returnKey,$resReturn] = $this->checkNextFlow($next,$nextId,$processId,$processReal,$processRealFlip,$treeFirstNode);
    369. }
    370. if($nodesInfo[$vvvNodeId]["info_talk_info"]) {//如果是跳转节点,没有输入声音就是不输入
    371. if($count==1){
    372. $vvvNodeId .= "_".$version;
    373. }
    374. $flow["F" . $vvvNodeId] = $arg;
    375. }
    376. }
    377. }
    378. return [$flow,$nodeSynonymList,$firstNode];
    379. }
    380. //生成一个挂机节点
    381. public function addEndPoints($flow)
    382. {
    383. /**
    384. * 生成一个挂机节点
    385. */
    386. $endPointsArray = [
    387. 'action'=>'hangup',
    388. 'position'=>[
    389. "x"=>67,
    390. "y"=>33
    391. ]
    392. ];
    393. $flow["F9999999999999999999"]=$endPointsArray;
    394. return $flow;
    395. }
    396. //生成一个等待用户回答节点
    397. public function addWaitPoints($flow)
    398. {
    399. /**
    400. * 生成一个挂机节点
    401. */
    402. $endWaitArray = [
    403. 'action'=>"cti_play_and_detect_speech",
    404. "argument"=>"'1' '16' '' '' '' '' '' '' '' '' '' '' '' ''",
    405. "position"=>[
    406. "x"=>391833,
    407. "y"=>2372
    408. ],
    409. "playbacks"=>[],
    410. "description"=>"",
    411. "sourceflowdepth"=>"1",
    412. "globalflow"=>[
    413. "all"
    414. ],
    415. "kb" => 'C1',
    416. "kb_priority"=>2,
    417. "condition"=> [
    418. "complete"=> [],
    419. "text"=> []
    420. ],
    421. "timeoutrepetition"=>"",
    422. "mismatchplaybacks"=> [],
    423. "subflow"=>[]
    424. ];
    425. $flow["F88888888888888888888"]=$endWaitArray;
    426. // $flow["F66666666666666666666"]=[
    427. // "action"=> "return",
    428. // "position"=> [
    429. // "x"=> 2263,
    430. // "y"=> 492
    431. // ]
    432. // ];
    433. return $flow;
    434. }
    435. //生成一个挂机播放节点
    436. public function addHangUpPlayContent($flow,$nodeId,$playbacks)
    437. {
    438. $hangUpArray = [
    439. 'action'=>"cti_play_and_detect_speech",
    440. "argument"=>"'0' '16' '' '' '' '' '' '' '' '' '' '' '' ''",
    441. "position"=>[
    442. "x"=>391833,
    443. "y"=>2372
    444. ],
    445. "playbacks"=>$playbacks,
    446. "description"=>"",
    447. "sourceflowdepth"=>"1",
    448. "condition"=> [
    449. "text"=> []
    450. ],
    451. "mismatchplaybacks"=> [],
    452. "subflow"=>[
    453. "F9999999999999999999"=> [
    454. "condition"=>[
    455. "complete"=> [
    456. "any"
    457. ],
    458. ],
    459. ]
    460. ]
    461. ];
    462. $flow["F".$nodeId] = $hangUpArray;
    463. return $flow;
    464. }
    465. //生成一个挂机播放节点
    466. public function addHangUpPlay($flow)
    467. {
    468. $hangUpArray = [
    469. 'action'=>"cti_play_and_detect_speech",
    470. "argument"=>"'0' '16' '' '' '' '' '' '' '' '' '' '' '' ''",
    471. "position"=>[
    472. "x"=>391833,
    473. "y"=>2372
    474. ],
    475. "playbacks"=>[],
    476. "description"=>"",
    477. "sourceflowdepth"=>"1",
    478. "condition"=> [
    479. "text"=> []
    480. ],
    481. "mismatchplaybacks"=> [],
    482. "subflow"=>[
    483. "F9999999999999999999"=> [
    484. "condition"=>[
    485. "text"=> [
    486. "any"
    487. ],
    488. ],
    489. ]
    490. ]
    491. ];
    492. $flow["F5555555555555555555555"] = $hangUpArray;
    493. return $flow;
    494. }
    495. public function addWaitSubPoints(){
    496. return [
    497. "F9999999999999999999"=> [
    498. "condition"=>[
    499. "complete"=> [
    500. "timeout()"
    501. ]
    502. ],
    503. "description"=> "静音挂断"
    504. ],
    505. "F66666666666666666666"=>[
    506. "condition"=> [
    507. "complete"=> [],
    508. "text"=> [
    509. "F.+"
    510. ]
    511. ],
    512. "description"=> "有声音返回"
    513. ]
    514. ];
    515. }
    516. //生成一个挂机节点
    517. public function addHangUpPoints()
    518. {
    519. $endPointsArray["F9999999999999999999"] = [
    520. 'condition'=>[
    521. 'complete'=> [
    522. "any"
    523. ]
    524. ],
    525. ];
    526. return $endPointsArray;
    527. }
    528. //跳转到指定主流程
    529. public function toMainFlow($flowId)
    530. {
    531. $arg["F".$flowId]= [
    532. "condition"=>[
    533. "complete"=> [],
    534. "text"=>[
    535. "any"
    536. ],
    537. "description"=>""
    538. ]
    539. ];
    540. return $arg;
    541. }
    542. //跳转到指定多伦会话
    543. public function toMulFlow($flowId)
    544. {
    545. $arg["F".$flowId."_".$flowId]= [
    546. "condition"=>[
    547. "complete"=> [],
    548. "text"=>[
    549. "any"
    550. ],
    551. "description"=>""
    552. ]
    553. ];
    554. return $arg;
    555. }
    556. //判断主流程下个流程的节点
    557. public function checkNextFlow($next,$nextId,$process_id,$processReal,$processRealFlip,$treeFirstNode,$arrSubFlow=[])
    558. {
    559. $array = [];
    560. $keyNext = $processRealFlip[$process_id]+1;//下一个next
    561. $hangUp = $arrSubFlow?:["description"=>"无效回答", "condition"=>["text"=>["any"]]];
    562. $nextProcess = $arrSubFlow?: ["condition" => ["text" => ["any"]], "description" => "跳转下一个流程"];
    563. $keyReturn = "";
    564. $resReturn = "";
    565. switch ($next)
    566. {
    567. case 0:
    568. case 2:
    569. if(isset($processReal[$keyNext])){
    570. $array["F" . $treeFirstNode[$processReal[$keyNext]]["node_id"]] = $nextProcess;
    571. $keyReturn = $treeFirstNode[$processReal[$keyNext]]["node_id"];
    572. $resReturn = $nextProcess;
    573. }else{
    574. $array["F9999999999999999999"] = $hangUp;
    575. $keyReturn = "9999999999999999999";
    576. $resReturn = $hangUp;
    577. }
    578. break;
    579. case 1:
    580. $array["F9999999999999999999"] = $hangUp;
    581. $keyReturn = "9999999999999999999";
    582. $resReturn = $hangUp;
    583. break;
    584. case 3:
    585. if(isset($treeFirstNode[$nextId])) {
    586. $fistNode = $treeFirstNode[$nextId];
    587. $array["F" . $fistNode["node_id"]] = $nextProcess;
    588. $keyReturn = $fistNode["node_id"];
    589. $resReturn = $nextProcess;
    590. }else{
    591. $array["F9999999999999999999"] = $hangUp;
    592. $keyReturn = "9999999999999999999";
    593. $resReturn = $hangUp;
    594. }
    595. break;
    596. case 4://返回接口
    597. $keyReturn = substr(microtime(true),2,8).rand(0,99);
    598. $resReturn= [
    599. 'action' =>'return',
    600. 'position'=>[
    601. 'x'=>4085,
    602. 'y'=>377
    603. ],
    604. ];
    605. $array["F".$keyReturn] = $resReturn;
    606. break;
    607. }
    608. return [$array,$keyReturn,$resReturn];
    609. }
    610. //多伦会话匹配关键词结果数组
    611. public function getMulResultSynonym($speechId)
    612. {
    613. $resultSynonym = [];
    614. $synonymList = SpeechMulLabelSynonym::create()->getAll(["speech_id"=>$speechId]);
    615. foreach ($synonymList as $val){
    616. if(isset($val["sls_name"])) {
    617. $resultSynonym[$val["node_mul_id"]][$val["sls_keyword"]][] = $val["sls_name"];
    618. }
    619. }
    620. return $resultSynonym;
    621. }
    622. //获取所有子节点
    623. public function getMulProcessNodesNode($flow,$nodesMul,$resultMulSynonym,$childMulParent,$nodesMulInfo,$targetMulLabel,$nodeSynonymList,$treeFirstNode)
    624. {
    625. //判断是否有相同的节点
    626. $sameNodeList = [];
    627. $processMulNodesNode = [];
    628. $processMulNodesArr = [];//所有全局话术的根节点
    629. //用一个权重数组去获取最终值吧(始终取最大的)
    630. $priorityArray = [];
    631. foreach ($nodesMul as $key=>$value)
    632. {
    633. $valueProcessId = $value["process_mul_id"];
    634. $processMulNodesArr[$valueProcessId][] = $value;
    635. $subFlowModel = [];
    636. $valueNodesId = $value["nodes_id"];
    637. $valueParentId = $value["parent_id"];
    638. $valueNodeId = "F".$value["node_mul_id"]."_".$value["node_mul_id"];
    639. $priority = "0";
    640. if($valueNodesId) {
    641. $word = $targetMulLabel[$valueNodesId]??"";
    642. if ($word) {
    643. $synonymCode = "W." . $word;
    644. $yesSynonym = [];
    645. $isMore = 0;
    646. $arrSubFlow = [];
    647. $synonymArray = [];
    648. switch ($word){
    649. case "肯定":
    650. if(isset($resultMulSynonym[$childMulParent[$valueNodesId]]["yes"])) {
    651. $yesSynonym = array_values($resultMulSynonym[$childMulParent[$valueNodesId]]["yes"]);
    652. }
    653. $priority = "5";
    654. break;
    655. case "否定":
    656. if(isset($resultMulSynonym[$childMulParent[$valueNodesId]]["no"])) {
    657. $yesSynonym = array_values($resultMulSynonym[$childMulParent[$valueNodesId]]["no"]);
    658. }
    659. $priority = "10";
    660. break;
    661. case "拒绝":
    662. if(isset($resultMulSynonym[$childMulParent[$valueNodesId]]["reject"])) {
    663. $yesSynonym = array_values($resultMulSynonym[$childMulParent[$valueNodesId]]["reject"]);
    664. }
    665. $priority = "12";
    666. break;
    667. case "默认":
    668. $priority = "2";
    669. $isMore = 1;
    670. break;
    671. }
    672. if($isMore==0) {//不是默认
    673. $synonymSystem = $yesSynonym ?: [$synonymCode];
    674. foreach ($synonymSystem as $item){
    675. $synonymArray[$item] = $word;
    676. }
    677. $arrSubFlow = [
    678. "condition" => [
    679. "text" => $synonymSystem
    680. ],
    681. "priority" => $priority,
    682. "description" => $word
    683. ];
    684. }elseif($isMore==1){//是默认
    685. $arrSubFlow = [
    686. "condition" => [
    687. "text" => ["any"]
    688. ],
    689. "priority" => $priority,
    690. "description" => $word
    691. ];
    692. }
    693. if(!isset($priorityArray[$valueNodeId])) {
    694. $priorityArray[$valueNodeId] = $priority;
    695. }else{
    696. if($priorityArray[$valueNodeId]<$priority){
    697. $priorityArray[$valueNodeId] = $priority;
    698. }
    699. }
    700. if($nodesMulInfo[$value["node_mul_id"]]["info_talk_info"]) { //有信息的(多伦会话只要有信息判断)
    701. if(!isset($sameNodeList[$valueProcessId][$valueParentId][$valueNodeId])) {//是否存在当前流程,当前父id的,节点id
    702. //判断是否当前节点参数是否为空
    703. $subFlowModel[$valueNodeId] = $arrSubFlow;
    704. if($isMore==0) {//不是默认
    705. $nodeSynonymList[$valueNodeId] = $synonymArray;
    706. }
    707. $sameNodeList[$valueProcessId][$valueParentId][$valueNodeId] = $key+1;
    708. }else{
    709. if(!isset($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"])) {
    710. $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"] = [];
    711. }
    712. if($isMore==0) {//非默认
    713. if ($yesSynonym) {
    714. $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"] = array_merge($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"] ,$yesSynonym);
    715. }
    716. if (!$yesSynonym) {
    717. array_push($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"], "W." . $word);
    718. }
    719. $nodeSynonymList[$valueNodeId] = array_merge($nodeSynonymList[$valueNodeId],$synonymArray);
    720. }
    721. if($isMore==1) {//默认
    722. // $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"]= ["any"];
    723. array_push($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["condition"]["text"], "any");
    724. }
    725. if(!isset($processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["description"])) {
    726. $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["description"] = $word;
    727. }else{
    728. $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["description"] .= "," . $word;
    729. }
    730. $processMulNodesNode[$valueProcessId][$valueParentId][$valueNodeId]["priority"] = $priorityArray[$valueNodeId];
    731. }
    732. }
    733. elseif(!$nodesMulInfo[$value["node_mul_id"]]["info_talk_info"] && $nodesMulInfo[$value["node_mul_id"]]["type_id"]==2){
    734. $next = $nodesMulInfo[$value["node_mul_id"]]["next"]; //跳转的条件
    735. $nextId = $nodesMulInfo[$value["node_mul_id"]]["next_id"];//流程id
    736. [$arrSubFlows,$returnKey,$resReturn,$flow] = $this->checkNextMulFlow($next,$nextId,$treeFirstNode,$flow);
    737. if(!isset($sameNodeList[$valueProcessId][$valueParentId][$returnKey])) {
    738. //判断是否当前节点参数是否为空
    739. if($resReturn){
    740. if(!isset($subFlowModel["F" . $returnKey]["condition"]["text"])) {
    741. $subFlowModel["F" . $returnKey]["condition"]["text"] = [];
    742. }
    743. if($isMore==0) {//非默认
    744. if ($yesSynonym) {
    745. $subFlowModel["F" . $returnKey]["condition"]["text"] = array_merge($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"],$yesSynonym);
    746. }
    747. if (!$yesSynonym ) {
    748. array_push($subFlowModel ["F" . $returnKey]["condition"]["text"], "W." . $word);
    749. }
    750. }
    751. if($isMore==1) {//默认
    752. // $subFlowModel ["F" . $returnKey]["condition"]["text"]= ["any"];
    753. array_push($subFlowModel ["F" . $returnKey]["condition"]["text"], "any");
    754. }
    755. $subFlowModel["F" . $returnKey]["priority"] = $priorityArray[$valueNodeId];
    756. }
    757. if($isMore==0) {//不是默认
    758. $nodeSynonymList[$valueNodeId] = $synonymArray;
    759. }
    760. // $subFlowModel["F".$returnKey] = $resReturn;
    761. $sameNodeList[$valueProcessId][$valueParentId][$returnKey] = $key+1;
    762. }else{
    763. if(!isset($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"])) {
    764. $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"] = [];
    765. }
    766. if($isMore==0) {//非默认
    767. if ($yesSynonym) {
    768. $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"] = array_merge($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"],$yesSynonym);
    769. }
    770. if (!$yesSynonym ) {
    771. array_push($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"], "W." . $word);
    772. }
    773. $nodeSynonymList[$valueNodeId] = array_merge($nodeSynonymList[$valueNodeId],$synonymArray);
    774. }
    775. if($isMore==1) {//默认
    776. // $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"]= ["any"];
    777. array_push($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["condition"]["text"], "any");
    778. }
    779. if(!isset($processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["description"])){
    780. $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["description"] = ",".$word;
    781. }else{
    782. $processMulNodesNode[$valueProcessId][$valueParentId] ["F" . $returnKey]["description"] .= ",".$word;
    783. }
    784. $processMulNodesNode[$valueProcessId][$valueParentId]["F" . $returnKey]["priority"] = $priorityArray[$valueNodeId];
    785. }
    786. }
    787. }
    788. }
    789. if (!isset($processMulNodesNode[$valueProcessId][$valueParentId])) {
    790. $processMulNodesNode[$valueProcessId][$valueParentId] = $subFlowModel;
    791. } else {
    792. $processMulNodesNode[$valueProcessId][$valueParentId] = array_merge($processMulNodesNode[$valueProcessId][$valueParentId],$subFlowModel);
    793. }
    794. }
    795. return [$processMulNodesNode,$nodeSynonymList,$processMulNodesArr,$flow];
    796. }
    797. //获取所有的
    798. public function getMulFlowList($flow,$processMulNodesArr,$argMulArray,$nodesMulInfo,$treeFirstNode,$processMulNodesNode,$allNodeMulWavKey,$priority)
    799. {
    800. $count = 0;
    801. foreach ($processMulNodesArr as $ke=>$ve){
    802. foreach ($ve as $kkk=>$vvv){
    803. $vvvNodeId = $vvv["node_mul_id"];
    804. $count++;
    805. $arg = [];
    806. $arg["action"] = "cti_play_and_detect_speech";
    807. //模式
    808. $argM = $argMulArray[$vvvNodeId]["moshi"]??"1";
    809. $argLuZao = $argMulArray[$vvvNodeId]["luzao"]??"";
    810. $argKaiShi = $argMulArray[$vvvNodeId]["kaishi"]??"";
    811. $argTingZhi = $argMulArray[$vvvNodeId]["tingzhi"]??"";
    812. $argDengDai = $argMulArray[$vvvNodeId]["dengdai"]??"";
    813. $argZuiDa = $argMulArray[$vvvNodeId]["zuida"]??"";
    814. $argCanShu = $argMulArray[$vvvNodeId]["canshu"]??"";
    815. $argLuYin = $argMulArray[$vvvNodeId]["luyin"]??"";
    816. //挂机不需要这些参数
    817. if($nodesMulInfo[$vvvNodeId]['next']!=1) {
    818. $arg["filter"] = [
    819. "text" => "S",
    820. "dtmf" => "none"
    821. ];
    822. if ($priority == 1) {
    823. $arg["kb_priority"] = 0;
    824. } elseif ($priority == 2) {
    825. $arg["kb_priority"] = 1;
    826. }
    827. $arg["timeoutplaybacks"] = [];
    828. $arg["timeoutrepetition"] = "";
    829. $arg["mismatchplaybacks"] = [];
    830. $arg["mismatchrepetition"] = "1";
    831. $arg["kb"] = 'C1';
    832. $arg["globalflow"] = [
    833. "all"
    834. ];
    835. }else{//挂机节点不起用asr
    836. $argM = 0;
    837. }
    838. $arg["argument"] = "'$argM' '16' '' '$argLuZao' '' '$argKaiShi' '$argTingZhi' '$argDengDai' '$argZuiDa' '' '$argCanShu' '$argLuYin' '' ''";
    839. $arg["position"] = [
    840. "x"=>$nodesMulInfo[$vvvNodeId]["node_x"],
    841. "y"=>$nodesMulInfo[$vvvNodeId]["node_y"]];
    842. $arg["description"] = $nodesMulInfo[$vvvNodeId]["info_title"];
    843. if(isset($allNodeMulWavKey[$vvvNodeId]) && $allNodeMulWavKey[$vvvNodeId]) {
    844. $arg["playbacks"] = [$allNodeMulWavKey[$vvvNodeId]];
    845. }else{
    846. $arg["playbacks"] = [$nodesMulInfo[$vvvNodeId]["info_talk_info"]];
    847. }
    848. if(isset($processMulNodesNode[$vvv["process_mul_id"]][$vvvNodeId])) {
    849. $arg["subflow"] = $processMulNodesNode[$vvv["process_mul_id"]][$vvvNodeId];
    850. }else{
    851. $next = $nodesMulInfo[$vvvNodeId]["next"]; //跳转的条件
    852. $nextId = $nodesMulInfo[$vvvNodeId]["next_id"];//流程id
    853. [$arg["subflow"],$returnKey,$resReturn,$flow] = $this->checkNextMulFlow($next,$nextId,$treeFirstNode,$flow);
    854. }
    855. if($nodesMulInfo[$vvvNodeId]["info_talk_info"]) {//如果是跳转节点,没有输入声音就是不输入
    856. $keyNode = "F".$vvvNodeId."_".$vvvNodeId;
    857. $flow[$keyNode] = $arg;
    858. }
    859. }
    860. }
    861. return $flow;
    862. }
    863. //多伦会话下一步
    864. public function checkNextMulFlow($next,$nextId,$treeFirstNode,$flow)
    865. {
    866. $array = [];
    867. $info = ["description"=>"默认回答", "condition"=>["text"=>["any"]]];
    868. $keyReturn = "";
    869. $resReturn = "";
    870. switch ($next)
    871. {
    872. case 0://普通节点默认挂机
    873. case 1://挂机
    874. $hangK = substr(microtime(true),2,8).rand(0,99);
    875. $hangKey = "F".$hangK;
    876. $array[$hangKey] = $info;
    877. $keyReturn = $hangK;
    878. $resReturn = $info;
    879. //挂机节点需要添加挂机节点
    880. /**
    881. * 生成一个挂机节点
    882. */
    883. $endPointsArray = [
    884. 'action'=>'hangup',
    885. 'position'=>[
    886. "x"=>67,
    887. "y"=>33
    888. ]
    889. ];
    890. $flow[$hangKey]=$endPointsArray;
    891. break;
    892. case 2://跳转指定多伦会话
    893. $hangKey = "F".$nextId."_".$nextId;
    894. $array[$hangKey] = $info;
    895. $keyReturn = $nextId."_".$nextId;
    896. $resReturn = $info;
    897. break;
    898. case 3://指定主流程
    899. $hangKey = "F".$treeFirstNode[$nextId]['node_id'];
    900. $array[$hangKey] = $info;
    901. $keyReturn = $treeFirstNode[$nextId]['node_id'];
    902. $resReturn = $info;
    903. break;
    904. }
    905. return [$array,$keyReturn,$resReturn,$flow];
    906. }
    907. //所有的多伦会话节点流程
    908. public function getMulArgArray($where)
    909. {
    910. $argList = SpeechMulProcessSettingModel::create()->getAll($where,"set_key,set_value,node_mul_id");//所有的参数节点流程
    911. $argArray = [];
    912. foreach ($argList as $argK=>$argValue){
    913. $argArray[$argValue["node_mul_id"]][$argValue["set_key"]] = $argValue["set_value"];
    914. }
    915. return $argArray;
    916. }
    917. }

  • 相关阅读:
    ssdp协议搜索GB28181设备
    Java修仙之基础功法篇->构建者模式
    PyTorch Geometric (PyG) 安装教程
    web前端网页设计期末课程大作业:旅游网页主题网站设计——紫色的旅游开发景点网站静态模板(4页)HTML+CSS+JavaScript
    BUUCTF Misc 来首歌吧 & 荷兰宽带数据泄露 & 面具下的flag & 九连环
    如何评价GPT-4o?
    Conda Channel 介绍与配置
    多输入多输出 | MATLAB实现PSO-LSSVM粒子群优化最小二乘支持向量机多输入多输出
    外包干了三年,真废了。。。
    java计算机毕业设计心理学网站源程序+mysql+系统+lw文档+远程调试
  • 原文地址:https://blog.csdn.net/iyaosan/article/details/136423142