--- /dev/null
+<?php
+
+namespace App\Console\Commands;
+
+use App\Models\ChatLib;
+use App\Models\ChatLog;
+use Illuminate\Console\Command;
+
+class ChatlibDatabase extends Command {
+
+ /**
+ * The name and signature of the console command.
+ *
+ * @var string
+ */
+ protected $signature = 'chatlib:database';
+
+ /**
+ * The console command description.
+ *
+ * @var string
+ */
+ protected $description = 'Updates the ChatLib database';
+
+ /**
+ * Execute the console command.
+ *
+ * @return int
+ */
+ public function handle() {
+ $db = new ChatLib();
+
+ ChatLog::where('banned', '=', false)
+ ->whereNotNull('evaluated_at')
+ ->chunk(500, function ($msgs) use ($db) {
+ foreach ($msgs as $msg) {
+ $db->addMessage($msg);
+ }
+ });
+
+ $db->compile();
+
+ for ($i = 0; $i < 50; ++$i) {
+ $this->line($db->generate());
+ }
+
+ return 0;
+ }
+
+}
+
+?>
--- /dev/null
+<?php
+
+namespace App\Models;
+
+class ChatLib {
+
+ public function addMessage($msg) {
+ $tokens = array_values(array_filter(preg_split('/\b/', $msg->text_content)));
+ if (empty($tokens)) return;
+ $tokens [] = '';
+ foreach ($tokens as $num => $token) {
+ if ($num === 0) {
+ $this->addStart($token);
+ } else if ($num === 1) {
+ $this->addOne($tokens[0], $token);
+ } else if ($num === 2) {
+ $this->addOne($tokens[1], $token);
+ $this->addTwo($tokens[0], $tokens[1], $token);
+ } else {
+ $this->addOne($tokens[$num - 1], $token);
+ $this->addTwo($tokens[$num - 2], $tokens[$num - 1], $token);
+ $this->addThree($tokens[$num - 3], $tokens[$num - 2], $tokens[$num - 1], $token);
+ }
+ }
+ }
+
+ public function compile() {
+ $this->start = $this->index($this->start);
+ foreach ($this->one as $key => $value) {
+ $this->one[$key] = $this->index($this->one[$key]);
+ }
+ foreach ($this->two as $key => $value) {
+ $this->two[$key] = $this->index($this->two[$key]);
+ }
+ foreach ($this->three as $key => $value) {
+ $this->three[$key] = $this->index($this->three[$key]);
+ }
+ }
+
+ public function generate($limit = 50) {
+ $tokens = [];
+ $start = $this->randomStart();
+ $tokens[] = $start;
+ $generated = $start;
+ while (strlen($generated) < $limit) {
+ $next = $this->randomNext($tokens);
+ if (empty($next)) break;
+ $tokens[] = $next;
+ $generated .= $next;
+ }
+ return $generated;
+ }
+
+ private function index($arr) {
+ $result = [];
+ $sum = 0;
+ asort($arr);
+ foreach ($arr as $key => $weight) {
+ $lower = $sum;
+ $sum += $weight;
+ $result[] = [$key, $lower, $sum];
+ }
+ return $result;
+ }
+
+ private function randomStart() {
+ return $this->pick($this->start);
+ }
+
+ private function randomNext($tokens) {
+ $cnt = count($tokens);
+ if ($cnt >= 3) {
+ $cmb = $tokens[$cnt - 3].$tokens[$cnt - 2].$tokens[$cnt - 1];
+ if (isset($this->three[$cmb])) {
+ return $this->pick($this->three[$cmb]);
+ }
+ }
+ if ($cnt >= 2) {
+ $cmb = $tokens[$cnt - 2].$tokens[$cnt - 1];
+ if (isset($this->two[$cmb])) {
+ return $this->pick($this->two[$cmb]);
+ }
+ }
+ if ($cnt >= 1) {
+ $cmb = $tokens[$cnt - 1];
+ if (isset($this->one[$cmb])) {
+ return $this->pick($this->one[$cmb]);
+ }
+ }
+ return '';
+ }
+
+ private function pick($options) {
+ $max = end($options)[2];
+ $num = random_int(0, $max);
+ $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];
+ if ($cur_low > $num) {
+ $max_index = $cur_index;
+ } else if ($cur_high < $num) {
+ $min_index = $cur_index + 1;
+ } else {
+ $min_index = $cur_index;
+ break;
+ }
+ }
+ return $options[$min_index][0];
+ }
+
+ private function addStart($token) {
+ if (empty($token)) return;
+ if (!isset($this->start[$token])) {
+ $this->start[$token] = 1;
+ } else {
+ ++$this->start[$token];
+ }
+ }
+
+ private function addOne($one, $token) {
+ if (!isset($this->one[$one])) {
+ $this->one[$one] = [];
+ }
+ if (!isset($this->one[$one][$token])) {
+ $this->one[$one][$token] = 1;
+ } else {
+ ++$this->one[$one][$token];
+ }
+ }
+
+ private function addTwo($one, $two, $token) {
+ $cmb = $one.$two;
+ if (!isset($this->two[$cmb])) {
+ $this->two[$cmb] = [];
+ }
+ if (!isset($this->two[$cmb][$token])) {
+ $this->two[$cmb][$token] = 1;
+ } else {
+ ++$this->two[$cmb][$token];
+ }
+ }
+
+ private function addThree($one, $two, $three, $token) {
+ $cmb = $one.$two.$three;
+ if (!isset($this->three[$cmb])) {
+ $this->three[$cmb] = [];
+ }
+ if (!isset($this->three[$cmb][$token])) {
+ $this->three[$cmb][$token] = 1;
+ } else {
+ ++$this->three[$cmb][$token];
+ }
+ }
+
+ private $start = [];
+ private $one = [];
+ private $two = [];
+ private $three = [];
+
+}