public static function get_response($in_input) { if (JxBotConverse::user_input_looks_strange($in_input)) { return 'Your last comment looks a bit strange.'; } // ** configurable? /* cap general server requests (safety); should be configurable as people have different host specs; 300 recommended for small shared host */ $cap_bot_ipm = JxBotConfig::option('sys_cap_bot_ipm', 300); if ($cap_bot_ipm > 0) { $stmt = JxBotDB::$db->prepare('SELECT COUNT(*) FROM log WHERE stamp >= DATE_SUB(NOW(), INTERVAL 1 MINUTE)'); $stmt->execute(); $last_min_total = intval($stmt->fetchAll(PDO::FETCH_NUM)[0][0]); if ($last_min_total >= $cap_bot_ipm) { return 'Sorry, I\'m too busy to chat right now. Please come back later.'; } } /* count interaction */ JxBotDB::$db->exec('UPDATE stats SET interactions = interactions + 1'); /* start timer */ $start_time = microtime(true); /* initalize tracking variables */ JxBotConverse::$match_time = 0.0; JxBotConverse::$service_time = 0.0; JxBotConverse::$iq_score = 0.0; JxBotConverse::$category_stack = array(); $fault = false; /* run the bot */ try { $output = JxBotConverse::srai($in_input); } catch (Exception $err) { $output = $err->getMessage(); $fault = true; } /* end timer */ $end_time = microtime(true); //print 'IQ '.JxBotConverse::$iq_score. '<br>'; /* log this interaction */ if (trim($output) == '') { $fault = true; } if ($fault) { JxBotConverse::$iq_score = -1; } JxBotConverse::log($in_input, $output, $end_time - $start_time, JxBotConverse::$match_time, JxBotConverse::$service_time, JxBotConverse::$iq_score); /* return the bot response */ if ($fault) { return 'I do apologise. I seem to be experiencing a positronic malfunction.'; } return $output; }
<?php JxWidget::textfield(array('name' => 'input', 'label' => 'Administrator', 'max' => 150, 'autofocus' => true)); ?> <p><?php JxWidget::button('Talk'); ?> </p> <div class="left"> <img src="<?php print JxBotConfig::bot_url(); ?> jxbot/core/gfx/robot-small.png" id="chat-robot"> </div> <div class="bubble" style="max-width: 80%;"> <div class="bubble-top"><div class="bubble-corner-tl"></div><div class="bubble-corner-tr"></div></div> <div class="bubble-left"></div> <div class="bubble-content"> <?php print $response; ?> </div>
} else { if (isset($_POST['bot_name'])) { //JxBotConfig::set_option('bot_name', $_POST['bot_name']); foreach ($_POST as $key => $value) { if (substr($key, 0, 4) == 'bot_') { JxBotConfig::set_option($key, $value); } } JxBotConfig::save_configuration(); } ?> <p><div class="field"><label for="bot_name">Bot Name: </label> <input type="text" name="bot_name" id="bot_name" size="40" value="<?php print JxBotConfig::option('bot_name'); ?> "></div></p> <div class="field"><label for="bot_birthday">Birthday: </label> <input type="text" name="bot_birthday" id="bot_birthday" size="12" value="<?php print JxBotConfig::option('bot_birthday'); ?> "> (YYYY/MM/DD)</div> <p><input type="submit" value="Save"></p> <?php }
?> </div> <h2>Language Processing</h2> <div class="field"><label for="pre_strip_accents">Strip Accents:</label> <?php JxWidget::toggle_switch('pre_strip_accents', JxBotConfig::option('pre_strip_accents')); ?> <br><small>(strip accents during normalisation; good for English)</small></div> <h2>Security</h2> <div class="field"><label for="sys_cap_bot_ipm">Bot Load Maximum: </label> <input type="text" name="sys_cap_bot_ipm" id="sys_cap_bot_ipm" size="6" value="<?php print JxBotConfig::option('sys_cap_bot_ipm'); ?> "><br><small>(interactions per minute; 0 = unlimited)</small></div> <div class="field"><label for="admin_timeout">Administration Timeout: </label> <input type="text" name="admin_timeout" id="admin_timeout" size="6" value="<?php print JxBotConfig::option('admin_timeout'); ?> "><br><small>(minutes; 0 = no timeout)</small></div> <p class="left" id="buttons"><button type="submit" name="action" value="save">Save</button></p>
public function generate($in_context) { switch ($this->name) { case 'system': /* security implications; will not implement until reasonable controls are developed and an on/off switch */ /* security implications; will not implement until reasonable controls are developed and an on/off switch */ case 'javascript': /* server-side javascript is not implemented */ break; case 'think': $this->text_value($in_context); break; case 'template': case 'gossip': /* doesn't do anything in this AIML interpreter and is removed in AIML 2.0 */ /* doesn't do anything in this AIML interpreter and is removed in AIML 2.0 */ case 'x-learn-1': /* AIML 1 learn tag to be filtered on import and contents passed through without further action */ return $this->text_value($in_context); case 'random': $count = $this->child_element_count(); $index = mt_rand(1, $count) - 1; return $this->child_element($index)->text_value($in_context); case 'condition': $loop = false; // preparation for AIML 2 loop; will need to keep a stack & check the stack so it can be toggled // by a <loop/> element anywhere in the depth of the <li> do { $count = $this->child_element_count('li'); if ($count == 0) { $predicate = $this->child_or_attr_named($in_context, 'name'); $value = JxBotConverse::predicate($predicate); $pattern = $this->child_or_attr_named($in_context, 'value'); if (JxBotElement::matches_simple_pattern($value, $pattern)) { return $this->text_value($in_context, array('name', 'value')); } } else { $count = $this->child_element_count(); $predicate = $this->child_or_attr_named($in_context, 'name', null); if ($predicate !== null) { $value = JxBotConverse::predicate($predicate); for ($i = 0; $i < $count; $i++) { $item = $this->child_element($i); $pattern = $item->child_or_attr_named($in_context, 'value', null); if ($pattern === null) { return $item->text_value($in_context, array('value')); } if (JxBotElement::matches_simple_pattern($value, $pattern)) { return $item->text_value($in_context, array('value')); } } } else { for ($i = 0; $i < $count; $i++) { $item = $this->child_element($i); $predicate = $item->child_or_attr_named($in_context, 'name'); $value = JxBotConverse::predicate($predicate); $pattern = $item->child_or_attr_named($in_context, 'value', null); if ($pattern === null) { return $item->text_value($in_context, array('value', 'name')); } if (JxBotElement::matches_simple_pattern($value, $pattern)) { return $item->text_value($in_context, array('value', 'name')); } } } } } while ($loop); break; case 'star': case 'thatstar': case 'topicstar': $index = intval($this->child_or_attr_named($in_context, 'index', 1)); return $this->get_capture($in_context, $this->name, $index); case 'srai': return JxBotConverse::srai($this->text_value($in_context)); case 'sr': /* srai star /srai */ return JxBotConverse::srai($this->get_capture($in_context, 'star', 1)); case 'bot': case 'get': $name = trim($this->child_or_attr_named($in_context, 'name')); if ($name !== '') { if ($this->name == 'get') { return JxBotConverse::predicate($name); } else { if ($name == 'size') { return JxBotNLData::pattern_count(); } else { if ($name == 'age') { return JxBotElement::compute_age(); } else { if ($name == 'birthday') { return JxBotElement::birthday(); } else { return JxBotConfig::predicate($name); } } } } } break; case 'tag': /* non-standard Tag feature */ $name = trim($this->child_or_attr_named($in_context, 'name')); return $in_context->tag_value($name); case 'id': return JxBotConverse::predicate('id'); case 'size': /* we return the number of patterns, which is equivalent to AIML standard category count; since in JxBot one category != one pattern. */ return JxBotNLData::pattern_count(); case 'vocabulary': return JxBotNLData::word_count(); case 'version': return JxBot::VERSION; case 'program': return JxBot::PROGRAM . ' ' . JxBot::VERSION; case 'set': $name = trim($this->child_or_attr_named($in_context, 'name')); if ($name != '') { $value = $this->text_value($in_context, array('name')); JxBotConverse::set_predicate($name, $value); return $value; } break; case 'date': $php_format = 'r'; /* default - AIML 1.0 - we specify date & time format */ return date($php_format); case 'uppercase': return JxBotNL::upper($this->text_value($in_context)); case 'lowercase': return JxBotNL::lower($this->text_value($in_context)); case 'formal': return JxBotNL::formal($this->text_value($in_context)); case 'sentence': return JxBotNL::sentence($this->text_value($in_context)); case 'explode': return JxBotNL::explode($this->text_value($in_context)); case 'normalize': return JxBotNL::template_normalize($this->text_value($in_context)); case 'denormalize': return JxBotNL::template_denormalize($this->text_value($in_context)); case 'gender': if (count($this->children) == 0) { return JxBotNL::remap('gender', $this->get_capture($in_context, 'star', 1)); } return JxBotNL::remap('gender', $this->text_value($in_context)); case 'person': if (count($this->children) == 0) { return JxBotNL::remap('person', $this->get_capture($in_context, 'star', 1)); } return JxBotNL::remap('person', $this->text_value($in_context)); case 'person2': if (count($this->children) == 0) { return JxBotNL::remap('person2', $this->get_capture($in_context, 'star', 1)); } return JxBotNL::remap('person2', $this->text_value($in_context)); case 'map': $map_name = $this->child_or_attr_named($in_context, 'name'); return JxBotNL::remap($map_name, $this->text_value($in_context, array('name'))); case 'that': $indicies = JxBotElement::indicies($this->child_or_attr_named($in_context, 'index')); $in_response = count($indicies) >= 1 ? $indicies[0] : 1; $in_sentence = count($indicies) >= 2 ? $indicies[1] : 1; $response = JxBotConverse::history_response($in_response - 1); $sentences = JxBotNL::split_sentences($response); if ($in_sentence < 1 || $in_sentence > count($sentences)) { return ''; } return $sentences[$in_sentence - 1]; case 'input': $indicies = JxBotElement::indicies($this->child_or_attr_named($in_context, 'index')); $in_request = count($indicies) >= 1 ? $indicies[0] : 1; $in_sentence = count($indicies) >= 2 ? $indicies[1] : 1; $request = JxBotConverse::history_request($in_request - 1); $sentences = JxBotNL::split_sentences($request); if ($in_sentence < 1 || $in_sentence > count($sentences)) { return ''; } return $sentences[$in_sentence - 1]; case 'request': $index = intval($this->child_or_attr_named($in_context, 'index', 1)); return JxBotConverse::history_request($index - 1); case 'response': $index = intval($this->child_or_attr_named($in_context, 'index', 1)); return JxBotConverse::history_response($index - 1); default: /* push unknown content & tags through to output */ // ! REVIEW: A better policy might be to tightly control which tags are // allowed through, or provide an appropriate system option. return $this->flatten(); } }
} JxBotConfig::save_configuration(); } ?> <div class="field"><label for="bot_active">Online:</label> <?php JxWidget::toggle_switch('bot_active', JxBotConfig::option('bot_active')); ?> </div> <div class="field"><label for="admin_user">Administration Username: </label> <input type="text" name="admin_user" id="admin_user" size="20" value="<?php print JxBotConfig::option('admin_user'); ?> "></div> <div class="field"><label for="bot_password">Change Password: </label> <input type="text" name="bot_password" id="bot_password" size="20"></div> <p class="left" id="buttons"><button type="submit" name="action" value="save">Save</button></p> <?php } }
private static function page_complete() { ?> <h1>Installation Complete!</h1> <p>Installation was successful.</p> <p>You can now <a href="<?php print JxBotConfig::bot_url(); ?> jxbot/">login to your bot's administration panel</a> to upload AIML and further configure your bot.</p> <?php }
public static function normalise($in_input) { //if ($in_keep_wildcards) return JxBotNL::normalise_pattern($in_input); /* preparation */ $output = ' ' . $in_input . ' '; // leading & trailing space to help with substitution matching // consider replacing vertical & unusual horizontal whitespace (tabs) with all spaces here $output = JxBotNL::upper($output); /* do `tagging` in a different routine; really a pre-normalisation function */ /* `substitution` normalisations; substitutions, abbreviations, spelling */ $output = JxBotNL::apply_substitutions($output); /* `pattern fitting` normalisations */ if (JxBotConfig::option('pre_strip_accents', 0) == 1) { $output = JxBotNL::strip_accents($output); } $output = JxBotNL::strip_punctuation($output); $output = JxBotNL::split_words($output); return $output; }
JxBotConfig::save_configuration(); } if (isset($_REQUEST['del-name']) && trim($_REQUEST['del-name']) !== '') { JxBotConfig::bot_delete_prop($_REQUEST['del-name']); JxBotConfig::save_configuration(); } if (isset($_POST['action']) && $_POST['action'] == 'Save') { //JxBotConfig::set_option('bot_name', $_POST['bot_name']); foreach ($_POST as $key => $value) { if (substr($key, 0, 4) == 'bot_') { JxBotConfig::set_option($key, $value); } } JxBotConfig::save_configuration(); } $bot_properties = JxBotConfig::bot_properties(); $rows_per_col = ceil(count($bot_properties) / 2.0); function editable_section(&$properties, $row_count) { if (count($properties) == 0) { return; } print '<table>'; for ($i = 0; $i < $row_count; $i++) { $prop = array_shift($properties); if ($prop === null) { break; } print '<tr>'; print '<td style="width: 10em;">' . $prop[1] . '</td>'; print '<td><input type="text" name="' . $prop[0] . '" size="20" value="' . $prop[2] . '" style="width:95%"></td>';
public static function widget_timezone() { ?> <select name="bot_tz" id="bot_tz"> <option value=""></option> <?php $timezone_identifiers = DateTimeZone::listIdentifiers(); foreach ($timezone_identifiers as $tz) { print '<option value="' . $tz . '" ' . (JxBotConfig::option('bot_tz') == $tz ? ' selected="true"' : '') . '>' . $tz . '</option>'; } ?> </select> <?php }
function show_process_status() { $stmt = JxBotDB::$db->prepare('SELECT COUNT(*) FROM file WHERE last_update > DATE_SUB(NOW(), INTERVAL 20 SECOND)'); $stmt->execute(); $recent_status_changes = $stmt->fetchAll(PDO::FETCH_NUM)[0][0] != 0; ?> <h2>Status</h2> <?php if ($recent_status_changes == false) { ?> Idle. <?php } else { ?> <p style="margin-top: -20px; "><img src="<?php print JxBotConfig::bot_url(); ?> jxbot/core/gfx/43.GIF" style="vertical-align: middle; margin-right: 1.5em"> <?php $stmt = JxBotDB::$db->prepare('SELECT status,name FROM file WHERE status LIKE \'Loading%\''); $stmt->execute(); $status = $stmt->fetchAll(PDO::FETCH_NUM); if (count($status) == 0) { $status = 'Checking...'; } else { $status = $status[0][0] . ', ' . $status[0][1]; } print $status; ?> </p> <script type="text/javascript"> // ! TODO: Can be improved with an AJAX call to avoid reloading the page window.setTimeout(function() { window.location = '?page=import'; }, 10000); </script> <?php } }
public static function check_and_login() { $inputs = JxBotUtil::inputs('username,password'); /* check the user hasn't logged in too often recently */ $stmt = JxBotDB::$db->prepare('SELECT COUNT(*) FROM login WHERE stamp > DATE_SUB(NOW(), INTERVAL 1 MINUTE) AND username=?'); $stmt->execute(array($inputs['username'])); $recent_logins = intval($stmt->fetchAll(PDO::FETCH_NUM)[0][0]); if ($recent_logins > 5) { return false; } /* are credentials wrong? */ if (JxBotConfig::option('admin_user') != $inputs['username'] || JxBotConfig::option('admin_hash') != hash('sha256', $inputs['password'])) { $stmt = JxBotDB::$db->prepare('INSERT INTO login (username, note) VALUES (?, ?)'); $stmt->execute(array($inputs['username'], 'failure')); return false; } /* do the login */ $_SESSION['jxbot-admin'] = 1; $stmt = JxBotDB::$db->prepare('INSERT INTO login (username, note) VALUES (?, ?)'); $stmt->execute(array($inputs['username'], 'success')); $_SESSION['jxbot-last'] = time(); /* generate the admin page */ JxBotAdmin::admin_generate(); return true; }
public static function init_client() { JxBotConfig::setup_environment(); }
public static function small_delete_icon() { print '<img src="' . JxBotConfig::bot_url() . 'jxbot/core/gfx/delete16.png" alt="Delete">'; }
JxBotConfig::def_delete_pred($_REQUEST['del-name']); } if (isset($_POST['save'])) { foreach ($_POST as $key => $value) { if (substr($key, 0, 4) == 'def_') { JxBotConfig::set_option($key, $value); } } JxBotConfig::save_configuration(); } JxWidget::hidden('save', 1); ?> <?php $bot_properties = JxBotConfig::client_defaults(); $rows_per_col = ceil(count($bot_properties) / 2.0); function editable_section(&$properties, $row_count) { if (count($properties) == 0) { return; } print '<table>'; for ($i = 0; $i < $row_count; $i++) { $prop = array_shift($properties); if ($prop === null) { break; } print '<tr>'; print '<td style="width: 10em;">' . $prop[1] . '</td>'; print '<td><input type="text" name="' . $prop[0] . '" size="20" value="' . $prop[2] . '" style="width:95%"></td>';
public static function process_scheduled() { /* detatch from invoking HTTP process so we can't be interrupted */ JxBotAsyncLoader::detatch_http_request(); /* ensure we are the only instance running this process */ try { if (!JxBotExclusion::get_exclusive()) { return; } } catch (Exception $err) { JxBotAsyncLoader::log(JxBotAsyncLoader::LOG_LEVEL_ERROR, $err->getMessage(), ''); return; } /* iterate through all scheduled files */ while (true) { $stmt = JxBotDB::$db->prepare('SELECT name FROM file WHERE status = \'Scheduled\' ORDER BY name LIMIT 1'); $stmt->execute(); $next = $stmt->fetchAll(PDO::FETCH_NUM); if (count($next) == 0) { return; } /* we're done */ $file = $next[0][0]; /* flag the file to indicate we're processing it, and prevent a loop if something is amiss */ JxBotAsyncLoader::set_file_status($file, 'Loading'); /* does the file actually exist? */ $path = JxBotConfig::aiml_dir() . $file; if (!file_exists($path)) { JxBotAsyncLoader::set_file_status($file, 'Not Available'); continue; } /* run the AIML importer */ $importer = new JxBotAimlImport(); $result = $importer->import($path); // ! TODO: The notices, warnings and errors of this mechanism should be // sent to us via our log() method, not passed back in an array. ** /* check for errors and notices */ if (is_array($result)) { JxBotAsyncLoader::set_file_status($file, 'Loaded'); JxBotAsyncLoader::log(JxBotAsyncLoader::LOG_LEVEL_NOTICE, 'Loaded.', $file); /* log the results */ foreach ($result as $notice) { JxBotAsyncLoader::log(JxBotAsyncLoader::LOG_LEVEL_WARNING, $notice, $file); } } else { JxBotAsyncLoader::set_file_status($file, 'Load Error'); JxBotAsyncLoader::log(JxBotAsyncLoader::LOG_LEVEL_ERROR, $result, $file); } } }
protected function walk($in_parent_id, $in_term_index) { /* check search depth to prevent infinite recursion */ $this->search_depth++; if ($this->search_depth > JxBotEngine::MAX_SEARCH_DEPTH) { throw new Exception('Too much recursion (in pattern search)'); } /* look in this branch for all possible matching sub-branches; ie. an exact match with the input term, or, a wildcard or complex pattern term such as a bot property or AIML 2 'set' */ $stmt = JxBotDB::$db->prepare("SELECT id,expression,is_terminal FROM pattern_node \n\t\t\tWHERE parent=? AND ( (expression = ? AND sort_key IN (0,5)) OR (sort_key NOT IN (0,5)) ) \n\t\t\tORDER BY sort_key"); $current_term = $this->get_term($in_term_index); $stmt->execute(array($in_parent_id, $current_term)); $possible_branches = $stmt->fetchAll(PDO::FETCH_NUM); //print "Walk parent=$in_parent_id, term_index=$in_term_index, term=$current_term<br>"; //print '<pre>'; //var_dump($possible_branches); //print '</pre>'; foreach ($possible_branches as $possibility) { /* decode the possibility and prepare to match */ list($br_parent, $br_expr, $br_terminal) = $possibility; // in future, for speed, this information could be assessed at pattern registration // and stored & accessed, possibly using the sort key integer ? $is_wildcard = JxBotEngine::is_wildcard($br_expr); $set_ref = JxBotEngine::is_set_ref($br_expr); $bot_ref = JxBotEngine::is_bot_ref($br_expr); //print $br_expr; //print "Considering possible branch=$br_parent, expr=$br_expr, term=$br_terminal, wild=$is_wildcard :<br>"; // pattern side sets & bot tags will have to be handled similarly, since they may have multi-word values // basically, like wildcards, except all words must match /* branch to appropriate match handler depending on type of branch */ if ($bot_ref !== false || $set_ref !== false) { /* match: bot predicate or set reference: */ if ($bot_ref !== false) { $values = array(JxBotNL::normalise(JxBotConfig::bot($bot_ref))); $match = $this->try_match_values($br_parent, $values, false, $in_term_index, $br_terminal); } else { $values = JxBotNLData::set_values($set_ref); $match = $this->try_match_values($br_parent, $values, true, $in_term_index, $br_terminal); } } else { if (!$is_wildcard) { /* match: normal word or pattern clause separator: */ $match = $this->try_match_word($br_parent, $br_expr, $in_term_index, $br_terminal); } else { /* match: wildcard */ $match = $this->try_match_wildcard($br_parent, $br_expr, $in_term_index, $br_terminal); } } /* if matching was successful, return the matching pattern, otherwise, continue looking at sub-branches at this level */ if ($match !== false) { return $match; } } /* no possible subbranches; no match this branch */ $this->search_depth--; return false; }