/** * function run_spellcheck() * A function to run the spellchecking of the userinput * @param array $convoArr - the conversation array * @return $convoArr (spellchecked) **/ function run_spell_checker($convoArr) { $lookingfor = get_convo_var($convoArr, "aiml", "lookingfor"); $wordArr = explode(' ', $lookingfor); foreach ($wordArr as $index => $word) { $sentance .= spell_check($word, $convoArr['conversation']['bot_id']) . " "; } $convoArr['aiml']['lookingfor'] = $sentance; return $convoArr; }
/** * function log_conversation_state(() * A function to log the conversation * @param array $convoArr - the current state of the conversation array * @return $convoArr (updated) **/ function log_conversation_state($convoArr) { global $con, $dbn; //get undefined defaults from the db runDebug(__FILE__, __FUNCTION__, __LINE__, "logging state", 4); $serialise_convo = mysql_real_escape_string(serialize($convoArr)); $user_id = $convoArr['conversation']['user_id']; $bot_id = $convoArr['conversation']['bot_id']; $client_name = get_convo_var($convoArr, 'client_properties', 'name'); if (isset($client_name) && $client_name != "") { $sql_addon = "`name` = '" . mysql_real_escape_string($client_name) . "', "; } else { $sql_addon = ""; } $sql = "UPDATE `{$dbn}`.`users`\n SET \n `state` = '{$serialise_convo}', \n `last_update` = NOW(), \n {$sql_addon}\n `chatlines` = `chatlines`+1\n WHERE `id` = '{$user_id}' LIMIT 1"; runDebug(__FILE__, __FUNCTION__, __LINE__, "updating conversation state SQL: {$sql}", 3); db_query($sql, $con); return $convoArr; }
$convoArr = read_from_session(); //now overwrite with the recieved data $convoArr = check_set_bot($convoArr); $convoArr = check_set_convo_id($convoArr); $convoArr = check_set_user($convoArr); $convoArr = check_set_format($convoArr); $convoArr['time_start'] = $time_start; //if totallines = 0 then this is new user if (isset($convoArr['conversation']['totallines'])) { //reset the debug level here $debuglevel = get_convo_var($convoArr, 'conversation', 'debugshow', '', ''); } else { //load the chatbot configuration $convoArr = load_bot_config($convoArr); //reset the debug level here $debuglevel = get_convo_var($convoArr, 'conversation', 'debugshow', '', ''); //insita $convoArr = intialise_convoArray($convoArr); //add the bot_id dependant vars $convoArr = add_firstturn_conversation_vars($convoArr); $convoArr['conversation']['totallines'] = 0; $convoArr = get_user_id($convoArr); } $convoArr['aiml'] = array(); //add the latest thing the user said $convoArr = add_new_conversation_vars($say, $convoArr); //parse the aiml $convoArr = make_conversation($convoArr); $convoArr = log_conversation($convoArr); $convoArr = log_conversation_state($convoArr); $convoArr = write_to_session($convoArr);
/** * function aiml_to_phpfunctions() * This function performs a big find and replace on the aiml to convert it to php code * @param array $convoArr - the existing conversation array * @return array $convoArr **/ function aiml_to_phpfunctions($convoArr) { //TODO do we need this still? global $botsay, $srai_iterations, $error_response; //TODO read from bot vars runDebug(__FILE__, __FUNCTION__, __LINE__, "Converting the AIML to PHP code", 4); //extra debug info $msg = ""; $useStoredPHP = $convoArr['conversation']['use_aiml_code']; $uac = $convoArr['conversation']['update_aiml_code']; #$uac = 0; if ($convoArr['aiml']['aiml_to_php'] == "") { $msg .= " php code does not exist,"; } else { $msg .= " php code exists,"; } if ($useStoredPHP == 1) { $msg .= " Use stored php code is set to YES({$useStoredPHP})"; } else { $msg .= " Use stored php code is set to NO({$useStoredPHP})"; } if ($uac == 1) { $msg .= " update aiml to php is set to YES({$uac})"; } else { $msg .= " update aiml to php is set to NO({$uac})"; } //THIS MAY already have the code contained in the db in which case we can skip all of this //UNLESS - update_aiml_code is set to 1 this means we want to re-write it each time if ($convoArr['aiml']['aiml_to_php'] != "" and $uac == 0 and $useStoredPHP == 1) { runDebug(__FILE__, __FUNCTION__, __LINE__, "Using existing AIML to PHP code - {$msg}", 2); $parsed_template = get_convo_var($convoArr, 'aiml', 'aiml_to_php'); } else { runDebug(__FILE__, __FUNCTION__, __LINE__, "Generating new AIML to PHP code - {$msg}", 2); //load the existing aiml template $template = get_convo_var($convoArr, 'aiml', 'template'); //make stars, apostrophes and encode foriegn chars just to make everything safe before the big replace $template = str_replace("*", "\\*", $template); $template = str_replace("'", '~apos~', $template); $template = foreignchar_replace('encode', $template); $template = entity_replace('encode', $template); $i = 0; //to do this is in the add custom tags thing //start the find and replace $template = preg_replace('#<bot name="([^"]*)"/>#ie', "\$convoArr['bot_properties']['\$1']", $template); runDebug(__FILE__, __FUNCTION__, __LINE__, "Made initial bot property replacements", 4); $find[$i] = '#</say>#i'; $replace[$i] = '\';'; $i++; $find[$i] = '#<template>(\\s)*?</template>#i'; $replace[$i] = ''; $i++; $find[$i] = '#<template/>#i'; $replace[$i] = ''; $i++; $find[$i] = '#<say>#i'; $replace[$i] = '$tmp_botsay .= \''; $i++; $find[$i] = '#<bot name="([^"]*)"/>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'bot_properties\',\'$1\').\''; $i++; $find[$i] = '#<date format="([^"]*)"/>#i'; $replace[$i] = '\'.call_user_func(\'get_formatted_date\',\'$1\').\''; $i++; $find[$i] = '#<bigthink></bigthink>#i'; $replace[$i] = '; $tmp_botsay = ""; '; $i++; $find[$i] = '#<pushstack>(.*)([^<]*)</pushstack>#'; $replace[$i] = '\'.call_user_func(\'push_stack\',$convoArr,\'$1\').\''; $i++; $find[$i] = '#PUSH\\s?<([^>]*)>#'; $replace[$i] = '\'.call_user_func(\'push_stack\',$convoArr,\'<$1>\').\''; $i++; $find[$i] = '#POP\\s?<([^>]*)>#'; $replace[$i] = '\'.call_user_func(\'pop_stack\',$convoArr).\''; $i++; $find[$i] = '#<popstack></popstack>#'; $replace[$i] = '\'.call_user_func(\'pop_stack\',$convoArr).\''; $i++; $find[$i] = '#<personf/>#i'; $replace[$i] = '\'.call_user_func(\'url_encode_star\',$convoArr).\''; $i++; $find[$i] = '#<topic name=\\"(A-Z0-9)\\">#i'; $replace[$i] = '\'.call_user_func(\'set_topicname\',$convoArr,\'$1\').\''; $i++; $find[$i] = '#<star index="([^"]*?)"/>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'star\',\'\',\'$1\').\''; $i++; $find[$i] = '#<that index="(.*?),(.*?)"/>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'that\',\'\',\'$1\',\'$2\').\''; $i++; $find[$i] = '#<input index="([^"]*)"/>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'input\',\'\',\'$1\').\''; $i++; $find[$i] = '#<thatstar index="([^"]*)"/>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'that_star\',\'\',\'$1\').\''; $i++; $find[$i] = '#<topicstar index="([^"]*)"/>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'topic_star\',\'\',\'$1\').\''; $i++; $find[$i] = '#<get name="topic"(\\s)?(/)?>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'topic\').\''; $i++; $find[$i] = '#<get name="([^"]*)"(/)?>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'client_properties\',\'$1\').\''; $i++; $find[$i] = '#<id/>#i'; $replace[$i] = '\'.call_user_func(\'get_convo_var\',$convoArr,\'client_properties\',\'id\').\''; $i++; $find[$i] = '#<uppercase>([^<]*)</uppercase>#i'; $replace[$i] = '\'.call_user_func(\'format\',\'uppercase\',\'$1\').\''; $i++; $find[$i] = '#<lowercase>([^<]*)</lowercase>#i'; $replace[$i] = '\'.call_user_func(\'format\',\'lowercase\',\'$1\').\''; $i++; $find[$i] = '#<formal>([^<]*)</formal>#i'; $replace[$i] = '\'.call_user_func(\'format\',\'formal\',\'$1\').\''; $i++; $find[$i] = '#<sentence>([^<]*)</sentence>#i'; $replace[$i] = '\'.call_user_func(\'format\',\'sentence\',\'$1\').\''; $i++; $find[$i] = '#<srai>#i'; $replace[$i] = '\'.call_user_func(\'run_srai\',$convoArr,\''; $i++; $find[$i] = '#</srai>#i'; $replace[$i] = '\').\''; $i++; $find[$i] = '#<think>#i'; $replace[$i] = '\'.call_user_func(\'make_null\',\''; $i++; $find[$i] = '#</think>#i'; $replace[$i] = '\').\''; $i++; $find[$i] = '#<person>([^<]*)</person>#i'; $replace[$i] = '\'.call_user_func(\'transform_prounoun\',$convoArr,\'3\',\'$1\').\''; $i++; $find[$i] = '#<person2>([^<]*)</person2>#i'; $replace[$i] = '\'.call_user_func(\'transform_prounoun\',$convoArr,\'2\',\'$1\').\''; $i++; $find[$i] = '#<condition>[\\s]?<li name="([^"]*)" value="([^"]*)">#i'; $replace[$i] = "';\r\n" . ' if( ((isset($convoArr[\'$1\'])) && (strtoupper($convoArr[\'$1\']) === strtoupper(\'$2\'))) || ((isset($convoArr[\'client_properties\'][\'$1\'])) && (strtoupper($convoArr[\'client_properties\'][\'$1\']) === strtoupper(\'$2\'))) )' . "\r\n" . ' { $tmp_botsay .= \''; $i++; $find[$i] = '#<condition name="([^"]*)">#i'; $replace[$i] = "\r\n" . '; $condition = call_user_func(\'clean_condition\',\'$1\'); '; $i++; $find[$i] = '#<li name="([0-9a-z]*)" value="([0-9a-z]*)">#i'; $replace[$i] = "\r\n" . ' elseif( ((isset($convoArr[\'$1\'])) && (strtoupper($convoArr[\'$1\']) === strtoupper(\'$2\'))) || ((isset($convoArr[\'client_properties\'][\'$1\'])) && (strtoupper($convoArr[\'client_properties\'][\'$1\']) === strtoupper(\'$2\'))) )' . "\r\n" . ' { $tmp_botsay .= \''; $i++; $find[$i] = '#<li value="([^"]*)">#i'; $replace[$i] = "\r\n" . ' elseif( ((isset($convoArr[$condition])) && (strtoupper($convoArr[$condition]) === strtoupper(\'$1\'))) || ((isset($convoArr[\'client_properties\'][$condition])) && (strtoupper($convoArr[\'client_properties\'][$condition]) === strtoupper(\'$1\'))) )' . "\r\n" . ' { $tmp_botsay .= \''; $i++; $find[$i] = '#;(\\s|\\s+)?elseif#i'; $replace[$i] = ";\r\nif"; $i++; $find[$i] = "#<\random>(\\?|\\.|\\!\\s)?</li>#eis"; $replace[$i] = '</random>$1\';}'; //this has to be be evalutated immeditately as nothing will change we are just collecting a random value $i++; $find[$i] = "#<random>([^<]*)</random>#eis"; $replace[$i] = 'call_user_func(\'select_random\',\'$1\')'; // this needs a second attempt before i work out a proper fix // the first removes the out random but if there is a nested random it wont work $i++; $find[$i] = "#<random>(.*)</random>#eis"; $replace[$i] = 'call_user_func(\'select_random\',\'$1\')'; $i++; $find[$i] = '#<li>(.*)</li>#i'; $replace[$i] = "\r\n" . 'else { $tmp_botsay .=\'$1\'; } '; $i++; $find[$i] = '#</li>#i'; $replace[$i] = '\'; } '; $i++; $find[$i] = '#</condition>#i'; $replace[$i] = "\r\n" . '$condition = ""; '; //TODO WORK OUT WHY THIS OCCURES $i++; $find[$i] = '#</conditio#i'; $replace[$i] = "\r\n" . '$condition = ""; '; $i++; $find[$i] = '#<set name="([^"]*)">#i'; $replace[$i] = '\'.call_user_func(\'set_simple\',$convoArr,\'$1\',\''; $i++; $find[$i] = '#<set name=\\\\"([^\\\\]*)\\\\">#i'; $replace[$i] = '\'.call_user_func(\'set_simple\',$convoArr,\'$1\',\''; $i++; $find[$i] = '#</set>#i'; $replace[$i] = '\').\''; $i++; $find[$i] = '#</get>#i'; $replace[$i] = ''; $i++; $find[$i] = '#<system>\\s?(add|power|sqrt|divide|multiply|subtract)\\s?(.*)[\\s?](.*)</system>#i'; $replace[$i] = '\'.call_user_func(\'run_system\',\'$1\',\'$2\',\'$3\').\''; $i++; $find[$i] = '#<learn>\\s+?<category>\\s+?<pattern>\\s+?<eval>([^<]*)</eval>\\s+?</pattern>\\s+?<template>\\s+?<eval>([^<]*)</eval>\\s+?</template>\\s+?</category>\\s+?</learn>#ius'; $replace[$i] = '\'; call_user_func(\'make_learn\',$convoArr,\'$1\',\'$2\');'; runDebug(__FILE__, __FUNCTION__, __LINE__, "Built core tag array to make replacements", 4); //custom tags handled here $custom_tag_handle = custom_aiml_to_phpfunctions($find, $replace, $i); $find = $custom_tag_handle['find']; $replace = $custom_tag_handle['replace']; runDebug(__FILE__, __FUNCTION__, __LINE__, "Built custom tag array to make replacements", 4); runDebug(__FILE__, __FUNCTION__, __LINE__, "Looking to replace: " . print_r($find, true), 4); runDebug(__FILE__, __FUNCTION__, __LINE__, "With replacements: " . print_r($replace, true), 4); //actually do the find and replace here $parsed_template = preg_replace($find, $replace, $template); //clean up the find/replace code so that it can actaully evaluate as real php code $parsed_template = clean_for_eval($parsed_template, 0); //decode back before sending $parsed_template = entity_replace('decode', $parsed_template); $parsed_template = foreignchar_replace('decode', $parsed_template); //write to convoArr $convoArr['aiml']['aiml_to_php'] = $parsed_template; //update the aiml table $convoArr = add_aiml_to_php($convoArr); } //evaluate the generated code $botsay = eval_aiml_to_php_code($convoArr, $parsed_template); //if it works it works if not display error message //write the result (what the bot said) to the convoArr $convoArr['aiml']['parsed_template'] = $botsay . " "; runDebug(__FILE__, __FUNCTION__, __LINE__, "The bot will say: {$botsay}", 2); return $convoArr; }
/** * function url_encode_star() * This function encode the star value to make it safe for web addresses * @param array $convoArr - conversation array * @return string $encoded_star - the encoded string **/ function url_encode_star($convoArr) { $encoded_star = urlencode(get_convo_var($convoArr, 'star')); runDebug(__FILE__, __FUNCTION__, __LINE__, "Urlencoded the string to: {$encoded_star}", 4); return $encoded_star; }
/** * function find_aiml_matches() * This function builds the sql to use to get a match from the tbl * @param array $convoArr - conversation array * @return array $convoArr **/ function find_aiml_matches($convoArr) { global $con, $dbn, $error_response, $use_parent_bot; runDebug(__FILE__, __FUNCTION__, __LINE__, "Finding the aiml matches from the DB", 4); $i = 0; //TODO convert to get_it $bot_id = get_convo_var($convoArr, "conversation", "bot_id"); $bot_parent_id = get_convo_var($convoArr, "conversation", "bot_parent_id"); $default_aiml_pattern = get_convo_var($convoArr, "conversation", "default_aiml_pattern"); #$lookingfor = get_convo_var($convoArr,"aiml","lookingfor"); $lookingfor = mysql_real_escape_string(get_convo_var($convoArr, "aiml", "lookingfor")); //get the first and last words of the cleaned user input $lastInputWord = get_last_word($lookingfor); $firstInputWord = get_first_word($lookingfor); //get the stored topic $storedtopic = mysql_real_escape_string(get_convo_var($convoArr, "topic")); //get the cleaned user input $lastthat = get_convo_var($convoArr, 'that', '', 1, 1); //build like patterns if ($lastthat != "") { $thatPatternSQL = " OR " . make_like_pattern($lastthat, 'thatpattern'); } else { $thatPattern = ""; //$lastThatPattern = ""; //$firstThatPattern = ""; $thatPatternSQL = ""; //$storedthatpattern =""; } //get the word count $word_count = wordsCount_inSentance($lookingfor); if ($bot_parent_id != 0) { $sql_bot_select = " (bot_id = '{$bot_id}' OR bot_id = '{$bot_parent_id}') "; } else { $sql_bot_select = " bot_id = '{$bot_id}' "; } if ($word_count == 1) { //if there is one word do this $sql = "SELECT * FROM `{$dbn}`.`aiml` WHERE\n\t\t{$sql_bot_select} AND (\n\t\t((`pattern` = '_') OR (`pattern` = '*') OR (`pattern` = '{$lookingfor}') OR (`pattern` = '{$default_aiml_pattern}' ) )\n\t\tAND\t((`thatpattern` = '_') OR (`thatpattern` = '*') OR (`thatpattern` = '') OR (`thatpattern` = '{$lastthat}') {$thatPatternSQL} )\n\t\tAND ( (`topic`='') OR (`topic`='" . $storedtopic . "')))"; } else { //otherwise do this $sql_add = make_like_pattern($lookingfor, 'pattern'); $sql = "SELECT * FROM `{$dbn}`.`aiml` WHERE \n\t\t{$sql_bot_select} AND (\n\t\t((`pattern` = '_') OR \n\t\t (`pattern` = '*') OR \n\t\t (`pattern` like '{$lookingfor}') OR \n\t\t ({$sql_add}) OR \n\t\t (`pattern` = '{$default_aiml_pattern}' ))\n\t\tAND\t((`thatpattern` = '_') OR (`thatpattern` = '*') OR (`thatpattern` = '') OR (`thatpattern` = '{$lastthat}') {$thatPatternSQL} )\n\t\tAND ((`topic`='') OR (`topic`='" . $storedtopic . "')))"; } runDebug(__FILE__, __FUNCTION__, __LINE__, "Match AIML sql: {$sql}", 3); $result = db_query($sql, $con); if ($result && mysql_num_rows($result) > 0) { runDebug(__FILE__, __FUNCTION__, __LINE__, "FOUND: '" . mysql_num_rows($result) . "' potential AIML matches", 2); //loop through results while ($row = mysql_fetch_array($result)) { $allrows[$i]['aiml_id'] = $row['id']; $allrows[$i]['bot_id'] = $row['bot_id']; $allrows[$i]['pattern'] = $row['pattern']; $allrows[$i]['thatpattern'] = $row['thatpattern']; $allrows[$i]['template'] = $row['template']; $allrows[$i]['topic'] = $row['topic']; $allrows[$i]['aiml_to_php'] = $row['php_code']; $i++; } } else { runDebug(__FILE__, __FUNCTION__, __LINE__, "Error: FOUND NO AIML matches in DB", 1); $allrows[$i]['aiml_id'] = "-1"; $allrows[$i]['bot_id'] = "-1"; $allrows[$i]['pattern'] = "no results"; $allrows[$i]['thatpattern'] = ""; $allrows[$i]['template'] = "<say>{$error_response}</say>"; $allrows[$i]['topic'] = ""; $allrows[$i]['aiml_to_php'] = "\$botsay=\"{$error_response}\""; } return $allrows; }
/** * function handleDebug() * Handle the debug array at the end of the process * @param array $convoArr - conversation arrau * @return array $convoArr; * TODO THIS MUST BE IMPLMENTED **/ function handleDebug($convoArr) { global $debugArr; $convoArr['debug'] = $debugArr; $log = ''; foreach ($debugArr as $time => $subArray) { $log .= $time . "[NEWLINE]"; foreach ($subArray as $index => $value) { if ($index == "fileName" || $index == "functionName" || $index == "line") { $log .= "[" . $value . "]"; } elseif ($index == "info") { $log .= "[NEWLINE]" . $value . "[NEWLINE]-----------------------[NEWLINE]"; } } } $log .= "[NEWLINE]-----------------------[NEWLINE]"; $log .= "CONVERSATION ARRAY"; $log .= "[NEWLINE]-----------------------[NEWLINE]"; $debuglevel = get_convo_var($convoArr, 'conversation', 'debugshow', '', ''); if ($debuglevel == 4) { //show the full array $showArr = $convoArr; unset($showArr['debug']); } else { //show a reduced array $showArr = reduceConvoArr($convoArr); } $log .= print_r($showArr, true); switch ($convoArr['conversation']['debugmode']) { case 0: //show in source code $log = str_replace("[NEWLINE]", "\r\n", $log); display_on_page(0, $log); break; case 1: //write to log file $log = str_replace("[NEWLINE]", "\r\n", $log); writefile_debug($log); break; case 2: //show in webpage $log = str_replace("[NEWLINE]", "<br/>", $log); display_on_page(1, $log); break; case 3: //email to user $log = str_replace("[NEWLINE]", "\r\n", $log); email_debug($convoArr['conversation']['debugemail'], $log); break; } return $convoArr; }