class ChatLib {
+ public function __construct($size = 6) {
+ $this->size = $size;
+
+ $converted = [];
+ foreach ($this->categories as $category => $patterns) {
+ $converted_patterns = [];
+ foreach ($patterns as $pattern) {
+ $converted_patterns[] = '/\b'.$pattern.'\b/u';
+ }
+ $converted['%'.strtoupper($category).'%'] = $converted_patterns;
+ }
+ $this->categories = $converted;
+ }
+
public function addMessage(ChatLog $msg) {
$this->addText($msg->text_content);
}
if ($end - $i < 5) break;
}
}
+ $this->addExample(array_slice($tokens, 0, $num), $token);
}
}
public function compile() {
- foreach ($this->transitions as $key => $value) {
- $this->transitions[$key] = $this->index($this->transitions[$key]);
+ foreach ($this->transitions as $key => $values) {
+ $this->transitions[$key] = $this->index($values, 2);
if (empty($this->transitions[$key])) {
unset($this->transitions[$key]);
}
}
+ foreach ($this->examples as $key => $values) {
+ if (in_array($key, ['', ' '])) {
+ unset($this->examples[$key]);
+ continue;
+ }
+ $this->examples[$key] = $this->index($values, 1);
+ if (empty($this->examples[$key]) || (count($this->examples[$key]) === 1 && $this->examples[$key][0][0] === $key)) {
+ unset($this->examples[$key]);
+ }
+ }
}
public function generate($limit = 100) {
$data = [
'size' => $this->size,
'transitions' => $this->transitions,
+ 'examples' => $this->examples,
];
Storage::disk('chatlib')->put($name.'.json', json_encode($data));
}
$data = json_decode(Storage::disk('chatlib')->get($name.'.json'), true);
$this->size = $data['size'];
$this->transitions = $data['transitions'];
+ $this->examples = $data['examples'];
}
- private function index($arr) {
+ private function index($arr, $min_weight = 2) {
$result = [];
$sum = 0;
- foreach ($arr as $key => $entry) {
- $weight = $entry['count'];
- if ($weight == 1) continue;
+ foreach ($arr as $key => $weight) {
+ if ($weight < $min_weight) continue;
$lower = $sum;
$sum += $weight;
- $examples = [];
- if (is_array(end($entry['examples']))) {
- // already processed
- $examples = $entry['examples'];
- } else if ($key === ' ') {
- $examples = [[' ', 0, 1]];
- } else {
- $subsum = 0;
- foreach ($entry['examples'] as $example => $subweight) {
- $sublower = $subsum;
- $subsum += $subweight;
- $examples[] = [$example, $sublower, $subsum];
- }
- }
- $result[] = [$key, $lower, $sum, $examples];
+ $result[] = [$key, $lower, $sum];
}
return $result;
}
if (isset($this->transitions[$cmb])) {
$pick = $this->pick($this->transitions[$cmb]);
if (!is_null($pick)) {
- return $this->exampleOf($pick);
+ return $this->exampleOf($pick, $tokens);
}
}
}
private function pick($options) {
if (empty($options)) return null;
- $max = end($options)[2];
+ $max = end($options)[2] - 1;
$num = random_int(0, $max);
+ return static::search($options, $num);
+ }
+
+ public static function search($options, $num) {
$min_index = 0;
$max_index = count($options) - 1;
while ($min_index < $max_index) {
$cur_index = intval(($min_index + $max_index) / 2);
$cur_low = $options[$cur_index][1];
- $cur_high = $options[$cur_index][2];
+ $cur_high = $options[$cur_index][2] - 1;
if ($cur_low > $num) {
$max_index = $cur_index;
} else if ($cur_high < $num) {
}
private function addTransition($state, $next) {
- $cmb = $this->generalize($state);
- if (!isset($this->transitions[$cmb])) {
- $this->transitions[$cmb] = [];
+ $ctx = $this->generalize($state);
+ $cmb = $this->generalize([$next]);
+ if (!isset($this->transitions[$ctx])) {
+ $this->transitions[$ctx] = [];
+ }
+ if (!isset($this->transitions[$ctx][$cmb])) {
+ $this->transitions[$ctx][$cmb] = 1;
+ } else {
+ ++$this->transitions[$ctx][$cmb];
}
- $this->increment($this->transitions[$cmb], $next);
}
- private function increment(&$which, $token) {
- $generalized = $this->generalize([$token]);
- if (!isset($which[$generalized])) {
- $which[$generalized] = [
- 'count' => 1,
- 'examples' => [],
- ];
- $which[$generalized]['examples'][$token] = 1;
+ private function addExample($context, $token) {
+ $cmb = $this->generalize([$token]);
+ if (!isset($this->examples[$cmb])) {
+ $this->examples[$cmb] = [];
+ }
+ if (!isset($this->examples[$cmb][$token])) {
+ $this->examples[$cmb][$token] = 1;
} else {
- ++$which[$generalized]['count'];
- if (!isset($which[$generalized]['examples'][$token])) {
- $which[$generalized]['examples'][$token] = 1;
- } else {
- ++$which[$generalized]['examples'][$token];
- }
+ ++$this->examples[$cmb][$token];
}
}
$str .= $replaced;
}
foreach ($this->categories as $category => $patterns) {
- foreach ($patterns as $pattern) {
- $str = preg_replace('/\b'.$pattern.'\b/u', '%'.strtoupper($category).'%', $str);
- }
+ $str = preg_replace($patterns, $category, $str);
}
return $str;
}
- private function exampleOf($pick) {
- $example = $this->pick($pick[3]);
- return $example[0];
+ private function exampleOf($pick, $context) {
+ if (!isset($this->examples[$pick[0]])) {
+ return $pick[0];
+ }
+ if (isset($this->examples[$pick[0]])) {
+ $example = $this->pick($this->examples[$pick[0]]);
+ return $example[0];
+ }
+ return $pick[0];
}
- private $size = 7;
+ private $size;
private $transitions = [];
+ private $examples = [];
private $aliases = [
'chest' => ['kiste'],
'einen' => ['n', 'nen'],
'musik' => ['mukke'],
- 'schade' => ['schad'],
+ 'schade' => ['schad', 'schaade'],
];
private $categories = [
'wave' => [
'dennsenhi',
'dergoawave',
+ 'falcnwavehi',
'heyguys',
'holysm0heyguys',
'muftaahey',
'wuschlwave',
],
- 'zelda_boss' => [
+ 'zb' => [
'aga(hnim)?',
'armos( knights)?',
'arrghus',
'vit(reous|ty)',
],
- 'zelda_dungeon' => [
+ 'zd' => [
'eastern',
'desert( palace)?',
'gt',
'tt',
],
- 'zelda_item' => [
+ 'zi' => [
'(big|small|retro|generic) ?keys?',
'b[oö]gen',
'bombos',
'sword',
],
- 'zelda_location' => [
+ 'zl' => [
'big chest',
'bumper( cave)?( ledge)?',
'(hyrule)? ?castle ?(tower)?',