PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/chatbot/core/aiml/parse_aiml.php

https://gitlab.com/tutaalexandr/bot_local
PHP | 656 lines | 502 code | 20 blank | 134 comment | 50 complexity | b8a03e30edd51b05ebae6e3a613828dc MD5 | raw file
  1. <?php
  2. /***************************************
  3. * www.program-o.com
  4. * PROGRAM O
  5. * Version: 2.4.8
  6. * FILE: chatbot/core/aiml/parse_aiml.php
  7. * AUTHOR: Elizabeth Perreau and Dave Morton
  8. * DATE: MAY 17TH 2014
  9. * DETAILS: this file contains the functions used to convert aiml to php
  10. ***************************************/
  11. /**
  12. * function buildVerbList()
  13. *
  14. * @param string $name
  15. * @param string $gender
  16. * @internal param array $convoArr
  17. */
  18. function buildVerbList($name, $gender)
  19. {
  20. runDebug(__FILE__, __FUNCTION__, __LINE__, "Building the verb list. Name:$name. Gender:$gender", 4);
  21. // person transform arrays:
  22. $firstPersonPatterns = array();
  23. $firstPersonReplacements = array();
  24. $secondPersonKeyedPatterns = array();
  25. $secondPersonPatterns = array();
  26. $secondPersonReplacements = array();
  27. $thirdPersonReplacements = array();
  28. switch ($gender)
  29. {
  30. case "male" :
  31. $g3 = "he";
  32. $tpWord = 'third';
  33. break;
  34. case "female";
  35. $g3 = "she";
  36. $tpWord = 'third';
  37. break;
  38. default :
  39. $g3 = "they";
  40. $tpWord = 'second';
  41. }
  42. // Search and replacement templates - grouped in pairs/triplets
  43. // first to second/third
  44. $firstPersonSearchTemplate = '/\bi [word]\b/ui';
  45. $secondPersonKeyedReplaceTemplate = 'y%%ou [word]';
  46. $thirdPersonReplaceTemplate = "$g3 [word]";
  47. //second to first
  48. $secondPersonSearchTemplate = '/\byou [word]\b/ui';
  49. $firstPersonReplaceTemplate = 'I [word]';
  50. //second (reversed) to first
  51. $secondPersonSearchTemplateReversed = '/\b[word] you\b/ui';
  52. $firstPersonReplaceTemplateReversed = '[word] @II';
  53. $secondPersonKeyedSearchTemplate = '/\by%%ou [word]\b/ui';
  54. $secondPersonReplaceTemplate = 'you [word]';
  55. //the list of verbs is stored in the config folder
  56. $file = _CONF_PATH_ . "verbList.dat";
  57. $verbList = file($file, FILE_USE_INCLUDE_PATH | FILE_SKIP_EMPTY_LINES);
  58. //or exit("<br>Unable to open tr");
  59. sort($verbList);
  60. // fill the arrays
  61. foreach ($verbList as $line)
  62. {
  63. $line = rtrim($line, "\r\n");
  64. #print "line = |$line|<br />\n";
  65. if (empty ($line))
  66. continue;
  67. $firstChar = substr($line, 0, 1);
  68. if ($firstChar === '#')
  69. continue;
  70. if ($firstChar === '$')
  71. {
  72. $words = str_replace('$ ', '', $line);
  73. list($first, $third) = explode(', ', $words);
  74. $second = $first;
  75. }
  76. elseif ($firstChar === '~')
  77. {
  78. $words = str_replace('~ ', '', $line);
  79. $first = $words;
  80. $second = $first;
  81. $third = $first;
  82. }
  83. else
  84. {
  85. list($first, $second, $third) = explode(', ', $line);
  86. }
  87. // build first patterns to second (both keyed and non) patterns and replacements, and first patterns to third replacements
  88. $firstPersonPatterns[] = str_replace('[word]', $first, $firstPersonSearchTemplate);
  89. $secondPersonKeyedPatterns[] = str_replace('[word]', $second, $secondPersonKeyedSearchTemplate);
  90. $secondPersonReplacements[] = str_replace('[word]', $first, $secondPersonReplaceTemplate);
  91. $thirdPersonReplacements[] = str_replace('[word]', $tpWord, $thirdPersonReplaceTemplate);
  92. // build second patterns to first replacements - reversed (e.g. "would I") first
  93. $secondPersonPatterns[] = str_replace('[word]', $second, $secondPersonSearchTemplate);
  94. $firstPersonReplacements[] = str_replace('[word]', $first, $firstPersonReplaceTemplate);
  95. // build first patterns to third replacements
  96. }
  97. $_SESSION['verbList'] = true;
  98. // debugging - Let's see what the contents of the files are!
  99. $transformList = array('firstPersonPatterns' => $firstPersonPatterns, 'secondPersonKeyedPatterns' => $secondPersonKeyedPatterns, 'secondPersonReplacements' => $secondPersonReplacements, 'thirdPersonReplacements' => $thirdPersonReplacements, 'secondPersonPatterns' => $secondPersonPatterns, 'firstPersonReplacements' => $firstPersonReplacements);
  100. foreach ($transformList as $transform_index => $transform_value)
  101. {
  102. $_SESSION['transform_list'][$transform_index] = $transform_value;
  103. }
  104. }
  105. /**
  106. * function swapPerson()
  107. * @param array $convoArr
  108. * @param int $person
  109. * @param string $input
  110. * @return string $tmp
  111. **/
  112. function swapPerson($convoArr, $person, $input)
  113. {
  114. runDebug(__FILE__, __FUNCTION__, __LINE__, "Person:$person In:$input", 4);
  115. $name = $convoArr['client_properties']['name'];
  116. $gender = (isset($convoArr['client_properties']['gender'])) ? $convoArr['client_properties']['gender'] : 'unknown';
  117. $tmp = trim($input);
  118. if ((!isset ($_SESSION['transform_list'])) || ($_SESSION['transform_list'] == NULL))
  119. {
  120. buildVerbList($name, $gender);
  121. }
  122. // <person2> = swap first with second poerson (e.g. I with you)
  123. // <person> swap with third person (e.g. I with he,she,it)
  124. switch ($gender)
  125. {
  126. case "male" :
  127. $g1 = "his"; // Third person singular: masculine (Possessive pronoun)
  128. $g2 = "him"; // Third person singular: masculine (object)
  129. $g3 = "he"; // Third person singular: masculine (subject)
  130. $g4 = "his"; // Third person singular: neutral (Possessive adjective)
  131. break;
  132. case "female";
  133. $g1 = "hers"; // Third person singular: feminine (Possessive pronoun)
  134. $g2 = "her";; // Third person singular: feminine (object)
  135. $g3 = "she"; // Third person singular: feminine (subject)
  136. $g4 = "her"; // Third person singular: neutral (Possessive adjective)
  137. break;
  138. default :
  139. $g1 = "its"; // Third person singular: neutral (Possessive pronoun)
  140. $g2 = "it"; // Third person singular: neutral (object)
  141. $g3 = "it"; // Third person singular: neutral (subject)
  142. $g4 = "its"; // Third person singular: neutral (Possessive adjective)
  143. }
  144. # I am, am I, was I, I, my, mine, myself, me, ourselves, we, us, ours, our
  145. $simpleFirstPersonPatterns = array('/(\bi am\b)/ui', '/(\bam i\b)/ui', '/(\bwas i\b)/ui', '/(\bi\b)/ui', '/(\bmy\b)/ui', '/(\bmine\b)/ui', '/(\bmyself\b)/ui', '/(\byour\b)/ui', '/(\bme\b)/ui', '/(\bourselves\b)/ui', '/(\bwe\b)/ui', '/(\bus\b)/ui', '/(\bours\b)/ui', '/(\bour\b)/ui');
  146. $simpleSecondPersonKeyedReplacements = array('y%%ou are', 'are y%%ou', 'were y%%ou', 'y%%ou', 'yo%%ur', 'yo%%urs', 'y%%ourself', 'm%%y', 'y%%ou', 'y%%ourselves', 'y%%ou', 'y%%ou', 'y%%ours', 'y%%our');
  147. # you are, are you, were you, you, your, yours, yourself, thy, yourselves
  148. $simpleSecondPersonPatterns = array('/(\bare you\b)/ui', '/(\byou are\b)/ui', '/(\bwere you\b)/ui', '/(\byou\b)/ui', '/(\byour\b)/ui', '/(\byours\b)/ui', '/(\byourself\b)/ui', '/(\bthy\b)/ui', '/(\byourselves\b)/ui');
  149. $simpleFirstPersonKeyedReplacements = array('I%% am', 'am I%%', 'was I%%', 'I%%', 'm%%y', 'm%%ine', 'm%%yself', 'm%%y', 'o%%urselves');
  150. # I am, am I, will I, shall I, may I, might I, can I, could I, must I, should I, would I, need I, was I, ourselves, our, ours, I, me, my, mine, myself, we, us
  151. $simpleFirstToThirdPersonPatterns = array('/(\bi am\b)/ui', '/(\bam i\b)/ui', '/(\bwill i\b)/ui', '/(\bshall i\b)/ui', '/(\bmay i\b)/ui', '/(\bmight i\b)/ui', '/(\bcan i\b)/ui', '/(\bcould i\b)/ui', '/(\bmust i\b)/ui', '/(\bshould i\b)/ui', '/(\bwould i\b)/ui', '/(\bneed i\b)/ui', '/(\bwas i\b)/ui', '/(\bourselves\b)/ui', '/(\bour\b)/ui', '/(\bours\b)/ui', '/(\bme\b)/ui', '/(\bi\b)/ui', '/(\bmy\b)/ui', '/(\bmine\b)/ui', '/(\bmyself\b)/ui', '/(\bwe\b)/ui', '/(\bud\b)/ui');
  152. $simpleThirdPersonReplacements = array("$g3 is", "is $g3", 'will ' . $g3, 'shall ' . $g3, 'may ' . $g3, 'might ' . $g3, 'can ' . $g3, 'could ' . $g3, 'must ' . $g3, 'should ' . $g3, 'would ' . $g3, 'need ' . $g3, 'was ' . $g3, 'themselves', 'their', 'theirs', "$g2", "$g3", "$g4", "$g1", "$g2" . 'self', 'they', 'them');
  153. if ($person == 2)
  154. {
  155. // $tmp = preg_replace('/\byou and me\b/ui', 'you and IzI', $tmp);// fix the "Me and you" glitch
  156. $tmp = preg_replace($simpleFirstPersonPatterns, $simpleSecondPersonKeyedReplacements, $tmp);// simple first to keyed second transform
  157. $tmp = preg_replace($simpleSecondPersonPatterns, $simpleFirstPersonKeyedReplacements, $tmp);// "simple" second to keyed first transform
  158. $tmp = preg_replace($_SESSION['transform_list']['secondPersonPatterns'], $_SESSION['transform_list']['firstPersonReplacements'], $tmp);// second to first transform
  159. }
  160. elseif ($person == 3)
  161. {
  162. // first to third transform
  163. $tmp = preg_replace($simpleFirstToThirdPersonPatterns, $simpleThirdPersonReplacements, $tmp);// "simple" first to third transform
  164. $tmp = preg_replace($_SESSION['transform_list']['firstPersonPatterns'], $_SESSION['transform_list']['thirdPersonReplacements'], $tmp);
  165. }
  166. $tmp = str_replace('%%', '', $tmp); // remove token
  167. //debug
  168. // if (RUN_DEBUG) runDebug(4, __FILE__, __FUNCTION__, __LINE__,"<br>\nTransformation complete. was: $input, is: $tmp");
  169. return $tmp;
  170. //return
  171. }
  172. /**
  173. * function parse_matched_aiml()
  174. * This function controls and triggers all the functions to parse the matched aiml
  175. * @param array $convoArr - the conversation array
  176. * @param string $type - normal or srai
  177. * @return array $convoArr - the updated conversation array
  178. **/
  179. function parse_matched_aiml($convoArr, $type = "normal")
  180. {
  181. //which debug mode?
  182. runDebug(__FILE__, __FUNCTION__, __LINE__, "Run the aiml parse in $type mode (normal or srai)", 3);
  183. $convoArr = set_wildcards($convoArr);
  184. $convoArr = parse_aiml_as_XML($convoArr);
  185. if ($type != "srai")
  186. {
  187. runDebug(__FILE__, __FUNCTION__, __LINE__, "$type - Saving for next turn", 4);
  188. $convoArr = save_for_nextturn($convoArr);
  189. }
  190. else
  191. {
  192. runDebug(__FILE__, __FUNCTION__, __LINE__, "$type - Not saving for next turn", 4);
  193. }
  194. return $convoArr;
  195. }
  196. /**
  197. * function clean_that()
  198. * This function cleans the 'that' of html and other bits and bobs
  199. *
  200. * @param string $that - the string to clean
  201. * @param $file
  202. * @param $function
  203. * @param $line
  204. * @return string $that - the cleaned string
  205. */
  206. function clean_that($that, $file, $function, $line)
  207. {
  208. #runDebug(__FILE__, __FUNCTION__, __LINE__,"This was called from $file, function $function, line $line", 4);
  209. runDebug(__FILE__, __FUNCTION__, __LINE__,"Cleaning up the ~THAT~ tag: '$that'", 4);
  210. $original_that = $that;
  211. $that = str_replace("<br/>", ".", $that);
  212. $that = strip_tags($that);
  213. $that = normalize_text($that);
  214. runDebug(__FILE__, __FUNCTION__, __LINE__, "Cleaning Complete. output = '$that'", 4);
  215. return $that;
  216. }
  217. /**
  218. * function save_for_nextturn()
  219. * This function puts the bot results of an srai search into the main convoArr
  220. * @param array $convoArr - the conversation array
  221. * @return array $convoArr - the updated conversation array
  222. **/
  223. function save_for_nextturn($convoArr)
  224. {
  225. runDebug(__FILE__, __FUNCTION__, __LINE__, "Saving that and that_raw for next turn", 4);
  226. $savethis = $convoArr['aiml']['parsed_template'];
  227. $convoArr = push_on_front_convoArr('that_raw', $savethis, $convoArr);
  228. $convoArr = push_on_front_convoArr('that', $savethis, $convoArr);
  229. return $convoArr;
  230. }
  231. /**
  232. * function set_wildcards()
  233. * This function extracts wildcards from a patterns and puts their values in their associated array
  234. * @param array $convoArr - the conversation array
  235. * @return array $convoArr - the updated conversation array
  236. **/
  237. function set_wildcards($convoArr)
  238. {
  239. runDebug(__FILE__, __FUNCTION__, __LINE__, "Setting Wildcards", 2);
  240. //save_file(_LOG_PATH_ . 'convoarr.txt', print_r($convoArr, true));
  241. $aiml_pattern = $convoArr['aiml']['pattern'];
  242. $ap = trim($aiml_pattern);
  243. $ap = str_replace("+", "\+", $ap);
  244. $ap = str_replace(" * ", " (\S*) ", $ap);
  245. $ap = str_replace(" _ ", " (\S*) ", $ap);
  246. $ap = str_replace("* ", "(\S*) ", $ap);
  247. $ap = str_replace("_ ", "(\S*) ", $ap);
  248. $ap = str_replace(" *", " (.*)", $ap);
  249. $ap = str_replace(" _", " (.*)", $ap);
  250. $ap = str_replace("*", "(.*)", $ap);
  251. $ap = str_replace("_", "(.*)", $ap);
  252. $ap = str_replace("(\S(.*))", "(.*)", $ap);
  253. $ap = str_replace("(.(.*))", "(.*)", $ap);
  254. // Set pattern wildcards
  255. $pattern_wildcards = str_replace("_", "(.*)?", str_replace("*", "(.*)?", $aiml_pattern));
  256. if ($pattern_wildcards != $aiml_pattern)
  257. {
  258. runDebug(__FILE__, __FUNCTION__, __LINE__, "We have pattern stars to process!", 2);
  259. if (!isset ($convoArr['aiml']['user_raw']))
  260. {
  261. $checkagainst = $convoArr['aiml']['lookingfor'];
  262. }
  263. else
  264. {
  265. $checkagainst = $convoArr['aiml']['user_raw'];
  266. }
  267. runDebug(__FILE__, __FUNCTION__, __LINE__, "Checking '$ap' against '$checkagainst'.", 2);
  268. if (preg_match_all("~$ap~siu", $checkagainst, $matches))
  269. {
  270. runDebug(__FILE__, __FUNCTION__, __LINE__, print_r($matches, true), 2);
  271. for ($i = 1; $i < count($matches); $i++)
  272. {
  273. $curStar = trim($matches[$i][0]);
  274. $curStar = preg_replace('/[[:punct:]]/uis', ' ',$curStar);
  275. $curIndex = $i;
  276. runDebug(__FILE__, __FUNCTION__, __LINE__, "Adding $curStar to the star stack.", 2);
  277. $convoArr['star'][$i] = $curStar;
  278. }
  279. }
  280. else
  281. runDebug(__FILE__, __FUNCTION__, __LINE__, "Something is not right here.", 2);
  282. }
  283. // Set that stars (match against just the first instance of that for now - need to work out something for all instances, though)
  284. $aiml_thatpattern = $convoArr['aiml']['thatpattern'];
  285. $tp = trim($aiml_thatpattern);
  286. $tp = str_replace("+", "\+", $tp);
  287. /*
  288. $tp = str_replace("*", "(.*)", $tp);
  289. $tp = str_replace("_", "(.*)", $tp);
  290. */
  291. $tp = str_replace(" * ", " (\S*) ", $tp);
  292. $tp = str_replace(" _ ", " (\S*) ", $tp);
  293. $tp = str_replace("* ", "(\S*) ", $tp);
  294. $tp = str_replace("_ ", "(\S*) ", $tp);
  295. $tp = str_replace(" *", " (.*)", $tp);
  296. $tp = str_replace(" _", " (.*)", $tp);
  297. $tp = str_replace("*", "(.*)", $tp);
  298. $tp = str_replace("_", "(.*)", $tp);
  299. $thatpattern_wildcards = str_replace("_", "(.*)?", str_replace("*", "(.*)?", $aiml_thatpattern));
  300. if ($thatpattern_wildcards != $aiml_thatpattern)
  301. {
  302. runDebug(__FILE__, __FUNCTION__, __LINE__, "We have thatpattern stars to process!", 2);
  303. $that = $convoArr['that'][1];
  304. $checkagainst = implode_recursive(' ', $that, __FILE__, __FUNCTION__, __LINE__);
  305. runDebug(__FILE__, __FUNCTION__, __LINE__, "Checking '$tp' against '$checkagainst'.", 2);
  306. if (preg_match_all("~$tp~si", $checkagainst, $matches))
  307. #if (preg_match("~$tp~si", $checkagainst, $matches))
  308. {
  309. runDebug(__FILE__, __FUNCTION__, __LINE__, "Current THAT matches:\n" . print_r($matches, true), 2);
  310. for ($i = 1; $i < count($matches); $i++)
  311. {
  312. $curStar = trim($matches[$i][0]);
  313. $curStar = preg_replace('/[[:punct:]]/uis', ' ',$curStar);
  314. $curIndex = $i;
  315. runDebug(__FILE__, __FUNCTION__, __LINE__, "Adding $curStar to the that_star stack.", 2);
  316. $convoArr['that_star'][$i] = $curStar;
  317. }
  318. }
  319. else
  320. runDebug(__FILE__, __FUNCTION__, __LINE__, "Something is not right here.", 2);
  321. }
  322. return $convoArr;
  323. }
  324. /**
  325. * function run_srai()
  326. * This function controls the SRAI recursion calls
  327. * @param array $convoArr - a reference to the existing conversation array
  328. * @param string $now_look_for_this - the text to search for
  329. * @return string $srai_parsed_template - the result of the search
  330. **/
  331. function run_srai(&$convoArr, $now_look_for_this)
  332. {
  333. global $srai_iterations, $error_response, $dbConn, $dbn;
  334. $bot_parent_id = $convoArr['conversation']['bot_parent_id'];
  335. $bot_id = $convoArr['conversation']['bot_id'];
  336. if ($bot_parent_id != 0 and $bot_parent_id != $bot_id)
  337. {
  338. $sql_bot_select = " (bot_id = '$bot_id' OR bot_id = '$bot_parent_id') ";
  339. }
  340. else
  341. {
  342. $sql_bot_select = " bot_id = '$bot_id' ";
  343. }
  344. $bot_id = $convoArr['conversation']['bot_id'];
  345. runDebug(__FILE__, __FUNCTION__, __LINE__,'Checking for entries in the srai_lookup table.', 2);
  346. runDebug(__FILE__, __FUNCTION__, __LINE__,"google bot_id = $bot_id", 2);
  347. $lookingfor = $convoArr['aiml']['lookingfor'];
  348. //$now_look_for_this = strtoupper($now_look_for_this);
  349. $sql = "select `template_id` from `$dbn`.`srai_lookup` where `pattern` = '$now_look_for_this' and $sql_bot_select;";
  350. runDebug(__FILE__, __FUNCTION__, __LINE__,"lookup SQL = $sql", 2);
  351. $row = db_fetchAll($sql, null, __FILE__, __FUNCTION__, __LINE__);
  352. runDebug(__FILE__, __FUNCTION__, __LINE__,'Result = ' . print_r($row, true), 2);
  353. $num_rows = count($row);
  354. if ($num_rows > 0)
  355. {
  356. runDebug(__FILE__, __FUNCTION__, __LINE__,"Found $num_rows rows in lookup table: " . print_r($row, true), 2);
  357. $template_id = $row[0]['template_id'];
  358. runDebug(__FILE__, __FUNCTION__, __LINE__,"Found a matching entry in the lookup table. Using ID# $template_id.", 2);
  359. $sql = "select `template` from `$dbn`.`aiml` where `id` = '$template_id';";
  360. $row = db_fetch($sql, null, __FILE__, __FUNCTION__, __LINE__);
  361. runDebug(__FILE__, __FUNCTION__, __LINE__,"Row found in AIML for ID $template_id: " . print_r($row, true), 2);
  362. if (!empty($row))
  363. {
  364. $template = add_text_tags($row['template']);
  365. try
  366. {
  367. $sraiTemplate = new SimpleXMLElement($template, LIBXML_NOCDATA);
  368. }
  369. catch (exception $e)
  370. {
  371. trigger_error("There was a problem parsing the SRAI template as XML. Template value:\n$template", E_USER_WARNING);
  372. $sraiTemplate = new SimpleXMLElement("<text>$error_response</text>", LIBXML_NOCDATA);
  373. }
  374. $responseArray = parseTemplateRecursive($convoArr, $sraiTemplate);
  375. $response = implode_recursive(' ', $responseArray, __FILE__, __FUNCTION__, __LINE__);
  376. runDebug(__FILE__, __FUNCTION__, __LINE__,"Returning results from stored srai lookup.", 2);
  377. return $response;
  378. }
  379. }
  380. else
  381. {
  382. runDebug(__FILE__, __FUNCTION__, __LINE__,'No match found in lookup table.', 2);
  383. }
  384. runDebug(__FILE__, __FUNCTION__, __LINE__,"Nothing found in the SRAI lookup table. Looking for a direct pattern match for '$now_look_for_this'.", 2);
  385. $sql = "SELECT `id`, `pattern`, `thatpattern`, `topic` FROM `$dbn`.`aiml` where `pattern` = :pattern and $sql_bot_select order by `id` asc;";
  386. $result = db_fetchAll($sql, array(':pattern' => $now_look_for_this), __FILE__, __FUNCTION__, __LINE__);
  387. $num_rows = count($result);
  388. runDebug(__FILE__, __FUNCTION__, __LINE__,"Found $num_rows potential responses.", 2);
  389. $allrows = array();
  390. $i = 0;
  391. if ($num_rows > 0)
  392. {
  393. $tmp_rows = number_format($num_rows);
  394. runDebug(__FILE__, __FUNCTION__, __LINE__, "FOUND: ($tmp_rows) potential AIML matches", 2);
  395. //loop through results
  396. foreach ($result as $row)
  397. {
  398. $row['aiml_id'] = $row['id'];
  399. $row['score'] = 0;
  400. $row['track_score'] = '';
  401. $allrows[] = $row;
  402. $mu = memory_get_usage(true);
  403. if ($mu >= MEM_TRIGGER)
  404. {
  405. runDebug(__FILE__, __FUNCTION__, __LINE__,'Current operation exceeds memory threshold. Aborting data retrieval.', 0);
  406. break;
  407. }
  408. }
  409. }
  410. else
  411. {
  412. runDebug(__FILE__, __FUNCTION__, __LINE__, "Error: FOUND NO AIML matches in DB", 1);
  413. $allrows[$i]['aiml_id'] = "-1";
  414. $allrows[$i]['bot_id'] = "-1";
  415. $allrows[$i]['pattern'] = "no results";
  416. $allrows[$i]['thatpattern'] = '';
  417. $allrows[$i]['topic'] = '';
  418. }
  419. //unset all irrelvant matches
  420. $allrows = unset_all_bad_pattern_matches($convoArr, $allrows, $now_look_for_this);
  421. $arCount = count($allrows);
  422. if ($arCount == 0)
  423. {
  424. runDebug(__FILE__, __FUNCTION__, __LINE__, "Error: FOUND NO AIML matches in DB", 1);
  425. $allrows[$i]['aiml_id'] = "-1";
  426. $allrows[$i]['bot_id'] = "-1";
  427. $allrows[$i]['pattern'] = "no results";
  428. $allrows[$i]['thatpattern'] = '';
  429. $allrows[$i]['topic'] = '';
  430. }
  431. //score the relevant matches
  432. $allrows = score_matches($convoArr, $allrows, $now_look_for_this);
  433. //get the highest
  434. $allrows = get_highest_scoring_row($convoArr, $allrows, $lookingfor);
  435. if (isset($allrows['aiml_id']) && $allrows['aiml_id'] > 0)
  436. {
  437. $aiml_id = $allrows['aiml_id'];
  438. $pattern = $allrows['pattern'];
  439. $sql = "select `template` from `$dbn`.`aiml` where `id` = :id limit 1;";
  440. $row = db_fetch($sql, array(':id' => $aiml_id), __FILE__, __FUNCTION__, __LINE__);
  441. $template = add_text_tags($row['template']);
  442. try
  443. {
  444. $sraiTemplate = new SimpleXMLElement($template, LIBXML_NOCDATA);
  445. }
  446. catch (exception $e)
  447. {
  448. trigger_error("There was a problem parsing the SRAI template as XML. Template value:\n$template", E_USER_WARNING);
  449. $sraiTemplate = new SimpleXMLElement("<text>$error_response</text>", LIBXML_NOCDATA);
  450. }
  451. $responseArray = parseTemplateRecursive($convoArr, $sraiTemplate);
  452. $response = implode_recursive(' ', $responseArray, __FILE__, __FUNCTION__, __LINE__);
  453. try
  454. {
  455. // code to try here
  456. $sql = "insert into `$dbn`.`srai_lookup` (`id`, `bot_id`, `pattern`, `template_id`) values(null, :bot_id, :pattern, :template_id);";
  457. $sth = $dbConn->prepare($sql);
  458. $sth->bindValue(':bot_id', $bot_id);
  459. $sth->bindValue(':pattern', $pattern);
  460. $sth->bindValue(':template_id', $aiml_id);
  461. $sth->execute();
  462. $affectedRows = $sth->rowCount();
  463. if ($affectedRows > 0) runDebug(__FILE__, __FUNCTION__, __LINE__,"Successfully inserted entry for '$pattern'.", 1);
  464. }
  465. catch(Exception $e)
  466. {
  467. //something to handle the problem here, usually involving $e->getMessage()
  468. $err = $e->getMessage();
  469. runDebug(__FILE__, __FUNCTION__, __LINE__,"Unable to insert entry for '$pattern'! Error = $err.", 1);
  470. runDebug(__FILE__, __FUNCTION__, __LINE__,"SQL = $sql", 1);
  471. }
  472. runDebug(__FILE__, __FUNCTION__, __LINE__,"Returning results from stored srai lookup.", 2);
  473. return $response;
  474. }
  475. runDebug(__FILE__, __FUNCTION__, __LINE__, "Running SRAI $srai_iterations on $now_look_for_this", 3);
  476. runDebug(__FILE__, __FUNCTION__, __LINE__, $convoArr['aiml']['html_template'], 4);
  477. //number of srai iterations - will stop recursion if it is over 10
  478. $srai_iterations++;
  479. runDebug(__FILE__, __FUNCTION__, __LINE__, "Incrementing srai iterations to $srai_iterations", 4);
  480. if ($srai_iterations > 10)
  481. {
  482. runDebug(__FILE__, __FUNCTION__, __LINE__, "ERROR - Too much recursion breaking out", 1);
  483. $convoArr['aiml']['parsed_template'] = $error_response;
  484. return $error_response;
  485. }
  486. //$tmp_convoArr = array();
  487. $tmp_convoArr = $convoArr;
  488. if (!isset($tmp_convoArr['stack'])) $tmp_convoArr = load_blank_stack($tmp_convoArr);
  489. if (!isset($tmp_convoArr['topic']))
  490. {
  491. $tmp_convoArr['topic'] = array();
  492. $tmp_convoArr['topic'][1] = '';
  493. }
  494. $tmp_convoArr['aiml'] = array();
  495. $tmp_convoArr['that'][1][1] = "";
  496. //added
  497. $tmp_convoArr['aiml']['parsed_template'] = "";
  498. $tmp_convoArr['aiml']['lookingfor'] = $now_look_for_this;
  499. $tmp_convoArr['aiml']['pattern'] = $now_look_for_this;
  500. $tmp_convoArr['aiml']['thatpattern'] = $convoArr['aiml']['thatpattern'];
  501. $tmp_convoArr = get_aiml_to_parse($tmp_convoArr);
  502. $tmp_convoArr = parse_matched_aiml($tmp_convoArr, "srai");
  503. $srai_parsed_template = $tmp_convoArr['aiml']['parsed_template'];
  504. runDebug(__FILE__, __FUNCTION__, __LINE__, "SRAI Found. Returning '$srai_parsed_template'", 2);
  505. $convoArr['client_properties'] = $tmp_convoArr['client_properties'];
  506. $convoArr['topic'] = $tmp_convoArr['topic'];
  507. $convoArr['stack'] = $tmp_convoArr['stack'];
  508. $srai_iterations--;
  509. runDebug(__FILE__, __FUNCTION__, __LINE__, "Decrementing srai iterations to $srai_iterations", 4);
  510. return $srai_parsed_template . " ";
  511. }
  512. /**
  513. * Function push_stack
  514. *
  515. * * @param $convoArr
  516. * @param $item
  517. * @return mixed
  518. */
  519. function push_stack(& $convoArr, $item)
  520. {
  521. if ((trim($item)) != (trim($convoArr['stack']['top'])))
  522. {
  523. runDebug(__FILE__, __FUNCTION__, __LINE__, "Pushing $item onto to the stack", 4);
  524. $convoArr['stack']['last'] = $convoArr['stack']['seventh'];
  525. $convoArr['stack']['seventh'] = $convoArr['stack']['sixth'];
  526. $convoArr['stack']['sixth'] = $convoArr['stack']['fifth'];
  527. $convoArr['stack']['fifth'] = $convoArr['stack']['fourth'];
  528. $convoArr['stack']['fourth'] = $convoArr['stack']['third'];
  529. $convoArr['stack']['third'] = $convoArr['stack']['second'];
  530. $convoArr['stack']['second'] = $convoArr['stack']['top'];
  531. $convoArr['stack']['top'] = $item;
  532. }
  533. else
  534. {
  535. runDebug(__FILE__, __FUNCTION__, __LINE__, "Could not push empty item onto to the stack", 1);
  536. }
  537. return $item;
  538. }
  539. /**
  540. * function pop_stack()
  541. * This function pops an item off the stack
  542. * @param array $convoArr - conversation array
  543. * @return string $item - the popped item
  544. **/
  545. function pop_stack(& $convoArr)
  546. {
  547. $item = trim($convoArr['stack']['top']);
  548. runDebug(__FILE__, __FUNCTION__, __LINE__, "Popped $item off the stack", 4);
  549. $convoArr['stack']['top'] = $convoArr['stack']['second'];
  550. $convoArr['stack']['second'] = $convoArr['stack']['third'];
  551. $convoArr['stack']['third'] = $convoArr['stack']['fourth'];
  552. $convoArr['stack']['fourth'] = $convoArr['stack']['fifth'];
  553. $convoArr['stack']['fifth'] = $convoArr['stack']['sixth'];
  554. $convoArr['stack']['sixth'] = $convoArr['stack']['seventh'];
  555. $convoArr['stack']['seventh'] = $convoArr['stack']['last'];
  556. $convoArr['stack']['last'] = "om";
  557. return $item;
  558. }
  559. /**
  560. * function make_learn()
  561. * This function builds the sql insert a learnt aiml cateogry in to the db
  562. * @param array $convoArr - conversation array
  563. * @param string $pattern - the pattern we will insert
  564. * @param string $template - the template to insert
  565. **/
  566. function make_learn($convoArr, $pattern, $template)
  567. {
  568. global $dbConn, $dbn;
  569. runDebug(__FILE__, __FUNCTION__, __LINE__, "Making learn", 2);
  570. runDebug(__FILE__, __FUNCTION__, __LINE__, "Pattern: $pattern", 2);
  571. runDebug(__FILE__, __FUNCTION__, __LINE__, "Template: $template", 2);
  572. $pattern = normalize_text($pattern);
  573. $aiml = "<learn> <category> <pattern> <eval>$pattern</eval> </pattern> <template> <eval>$template</eval> </template> </category> </learn>";
  574. /** @noinspection PhpSillyAssignmentInspection */
  575. $aiml = $aiml;
  576. $pattern = $pattern . " ";
  577. $template = $template . " ";
  578. $u_id = $convoArr['conversation']['user_id'];
  579. $bot_id = $convoArr['conversation']['bot_id'];
  580. $sql = "INSERT INTO `$dbn`.`aiml_userdefined`
  581. VALUES
  582. (NULL, '$aiml','$pattern','$template','$u_id','$bot_id',NOW())";
  583. runDebug(__FILE__, __FUNCTION__, __LINE__, "Make learn SQL: $sql", 3);
  584. $sth = $dbConn->prepare($sql);
  585. $sth->execute();
  586. $numRows = $sth->rowCount();
  587. }
  588. /**
  589. * function math_functions()
  590. * This function runs the system math operations
  591. *
  592. * @param string $operator - maths operator
  593. * @param int $num_1 - the first number
  594. * @param int|string $num_2 - the second number
  595. * @internal param int $output - the result of the math operation
  596. *
  597. * @return float|int|number|string
  598. */
  599. function math_functions($operator, $num_1, $num_2 = "")
  600. {
  601. runDebug(__FILE__, __FUNCTION__, __LINE__, "Running system tag math $num_1 $operator $num_2", 4);
  602. $operator = (IS_MB_ENABLED) ? mb_strtolower($operator) : strtolower($operator);
  603. switch ($operator)
  604. {
  605. case "add" :
  606. $output = $num_1 + $num_2;
  607. break;
  608. case "subtract" :
  609. $output = $num_1 - $num_2;
  610. break;
  611. case "multiply" :
  612. $output = $num_1 * $num_2;
  613. break;
  614. case "divide" :
  615. if ($num_2 == 0)
  616. {
  617. $output = "You can't divide by 0!";
  618. }
  619. else
  620. {
  621. $output = $num_1 / $num_2;
  622. }
  623. break;
  624. case "sqrt" :
  625. $output = sqrt($num_1);
  626. break;
  627. case "power" :
  628. $output = pow($num_1, $num_2);
  629. break;
  630. default :
  631. $output = $operator . "?";
  632. }
  633. return $output;
  634. }
  635. ?>