Напевно, багато хто вже встиг помітити деякий нововведення на нашому сайті. Зараз я розповім, звідки пішли коріння, як працює бот і як наповнювалася база фраз. Зробити точно такого ж бота не складе труднощів, повірте.
коріння
Ідею додати на сайт бота підкинув благородний дон Virus-ON. так що все лаври йому.
Що ж потрібно для створення бота?
По-перше, база даних фраз - пам'ять бота, щоб він міг відповідати на повідомлення.
По-друге, деякий алгоритм вибору фраз - мозок бота, щоб він відповідав більш-менш в тему.
База даних. Частина 1
Волею випадку, довелося познайомитися з однією людиною, програмуючому під Android і моторошно ненавидить продукцію Apple. Однією з його розробок є VK iHA bot. исходники якого є на GitHub.
Сам додаток нам не цікаво, а ось база даних на перших порах була б вельми до речі. Її і візьмемо.
Формат бази такий:
повідомлення \ відповідь \ релевантність
приклад
привіт \ Привіт, радий тебе бачити! \ 3
як справи \ Справи відмінно! \ 2
я людина \ А я робот)) \ 2
Нам потрібно розпарсити цей файл, прибрати зайві посилання, імена, матюки (яких тут дуже багато) і зберегти все в іншому форматі, зрозумілому БД MySQL.
Скрипт на мові Scala:
import scala. collection. mutable. HashSet
import scala. io. Source
import java. io. File
object VkIHAbotDbExtractor # 123;
val filterWords = Array # 40; // тут перерахування відомих матюків для
def main # 40; args. Array # 91; String # 93; # 41; # 123;
var set = new HashSet # 91; Phrase # 93;
new File # 40; args # 40; 0 # 41; # 41;
filter # 40; _. endsWith # 40; ".bin" # 41; # 41;
foreach # 40; f => set = set ++ open # 40; f # 41; # 41;
override def toString # 40; # 41; = S "( '$ message', '$ answer'),"
У методі main ми перебираємо всі .bin файли в директорії і викликаємо для кожного такого файлу метод open. Метод open читає файл по рядках та перетворює рядок в клас Phrase. У класі Phrase ми розбиваємо рядок на повідомлення - відповідь.
По-суті спецсимволи для нашого бота - сміття. Йому не обов'язково знати, де у вхідному повідомленні стоїть кома, він повинен орієнтуватися за словами і цифрами. рядок
replaceAll # 40; "[^ \\ p \\ p] +". "" # 41;
якраз це і робить.
До слова, наш бот не розбирається, що перед ним: питання або твердження. Але він може зрозуміти це по спільним словами: що. де. як і т.д.
Після виконання скрипта, ми отримаємо такий висновок в SQL-форматі:
# 40; '0'. 'Гарне число ти написав.' # 41 ;.
# 40; '1'. 'У мене з цифрами проблеми.' # 41 ;.
Залишилося тільки створити таблицю в БД і залити дамп.
CREATE TABLE IF NOT EXISTS `bot` # 40;
`Id` int # 40; 11 # 41; NOT NULL AUTO_INCREMENT.
`Message` text NOT NULL.
`Answer` text NOT NULL.
PRIMARY KEY # 40; `id` # 41 ;.
FULLTEXT KEY `message` # 40; `message` # 41;
# 41; ENGINE = MyISAM DEFAULT CHARSET = utf8;
Алгоритм вибору фраз
Алгоритм простий. Користувач пише повідомлення, яке потім передається боту на обробку. Там ми прибираємо всі зайві символи з повідомлення і шукаємо в БД схожу запис. Знайшли одну - видаємо як відповідь. Знайшли кілька - вибираємо випадкову зі знайдених. Чи не знайшли нічого схожого - виводимо випадковий відповідь.
Тепер по порядку і з кодом.
1. Надійшло повідомлення, віддаємо його на фільтрацію:
private function filter # 40; $ message # 41; # 123;
$ Msg = mb_strtolower # 40; $ Message. 'UTF-8' # 41; ; // переводимо текст в нижній регістр
$ Msg = str_replace # 40; self. NAME. ','. ''. $ msg # 41; ; // прибираємо звернення до боту
$ Msg = preg_replace # 40; '# \ [C (. +?) \ [/ C \] # sui'. ''. $ msg # 41; ; // прибираємо цитату на випадок, якщо Magatino лінь натиснути Відповісти
$ Msg = preg_replace # 40; '/ [^ A-zа-я0-9] / u'. ''. $ msg # 41; ; // прибираємо всі спецсимволи
$ Msg = preg_replace # 40; '/ \ S + /'. ''. $ msg # 41; ; // кілька поспіль прогалин замінюємо на один
return trim # 40; $ msg # 41; ;
2. Вибираємо фразу за явною збігом:
SELECT `answer` FROM` bot` WHERE `message` =" привіт "ORDER BY RAND # 40; # 41; LIMIT 1
3. Якщо такий не знайшли, тоді скористаємося розумнішим варіантом:
SELECT `answer` FROM` bot`
WHERE MATCH # 40; `message` # 41; AGAINST # 40; "Привіт" IN NATURAL LANGUAGE MODE # 41;> 0
ORDER BY RAND # 40; # 41; LIMIT 1
4. Якщо і тут порожньо - вибираємо будь-яку відповідь з доступних:
SELECT `answer` FROM` bot` ORDER BY RAND # 40; # 41; LIMIT 1
Найцікавіший, ймовірно, другий запит. Він шукає збіги грунтуючись на природній мові. Ось відмінності:
Ось, власне, і весь мозок.
PHP клас Bot.class.php
Використовувати ось так (forum / say.php):
if # 40; $ Id == 226621 # 41; # 123; // id теми, де буде відповідати бот
$ Answer = Bot. byMessage # 40; $ msg # 41; -> getAnswer # 40; # 41; ;
`Text` = '". Mysql_real_escape_string # 40; $ Llogin. ','. $ answer # 41 ;. " '" # 41; ;
mysql_query # 40; "UPDATE` users` SET `lastdate` = '$ realtime' WHERE` id` = ' ". Bot. ID. " '" # 41; ;
База даних. Частина 2
Чотирьох тисяч повідомлень явно мало, потрібно поповнити базу чимось таким, що відповідає тематиці сайту. Парсити кожне повідомлення на форумі не кращий варіант - не ясно де питання, де відповідь. Але ось повідомлення, що містять цитату, нам цілком підходять. У них вже є питання і прям в тому ж повідомленні відповідь.
Спершу дістаємо з бази форуму всі повідомлення, що містять цитату:
SELECT `text` FROM` forum` WHERE `text` REGEXP '^ \\ [c (= | \]) *'
Потім зберігаємо дамп. У мене вийшов файл в 12 Мб, що містить 38 тисяч записів.
Тепер все це справа потрібно розпарсити. Знову кличемо на допомогу Scala.
import scala. collection. mutable. HashSet
import scala. io. Source
import java. io. File