Add static commands, common phrases and Phrases.txt

This commit is contained in:
eleksir
2021-12-31 20:01:59 +03:00
parent 352dc3b54c
commit b8291a4c3e
3 changed files with 298 additions and 94 deletions

115
Phrases.txt Normal file
View File

@@ -0,0 +1,115 @@
Что понимают мозги? Ключевые фразы.
-----------------------------------------------------------------------------------------------------------------------
* Обращение к боту по нику. Допускаются пробелы перед и после фразы. Работает в приватных и публичных чатах.
* ping или пинг или пинх
- Для приватных чатов допустимой являются нотации:
* команды без суффиксов, с любым количеством пробельных символов до команды. После команды опциональная точка и
любое количество пробельных символов.
* с префиксом в виде любого количества пробельных символов + имени бота + любое количество пробельных символов +
опциональньная запятая + любое количество пробельных символов. После команды опциональная точка и любое
количество пробельных символов.
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + команда + опциональная точка и любое количество пробельных символов.
- Для публичных чатов допустимой являются нотации:
* с префиксом в виде любого количества пробельных символов + имени бота + любое количество пробельных символов +
опциональньная запятая + любое количество пробельных символов. После команды опциональная точка и любое
количество пробельных символов.
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + команда + опциональная точка и любое количество пробельных символов.
Ответ на эту фразу - слово "Pong." если фраза была на английском языке или "Понг.", если фраза была на русском языке.
* pоng или понг или понх
- Для приватных чатов допустимой являются нотации:
* команды без суффиксов, с любым количеством пробельных символов до команды. После команды опциональная точка и
любое количество пробельных символов.
* с префиксом в виде любого количества пробельных символов + имени бота + любое количество пробельных символов +
опциональньная запятая + любое количество пробельных символов. После команды опциональная точка и любое
количество пробельных символов.
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + ping + опциональная точка и любое количество пробельных символов.
- Для публичных чатов допустимой являются нотации:
* с префиксом в виде любого количества пробельных символов + имени бота + любое количество пробельных символов +
опциональньная запятая + любое количество пробельных символов. После команды опциональная точка и любое
количество пробельных символов.
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + команда + опциональная точка и любое количество пробельных символов.
Ответ на эту фразу - слово "Wat?" если фраза была на английском языке или "Шта?", если фраза была на русском языке.
* halp или хэлп
- Для приватных чатов допустимой являются нотации:
* команды без суффиксов, с любым количеством пробельных символов до команды. После команды опциональная точка и
любое количество пробельных символов.
* с префиксом в виде любого количества пробельных символов + имени бота + любое количество пробельных символов +
опциональньная запятая + любое количество пробельных символов. После команды опциональная точка и любое
количество пробельных символов.
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + команда + опциональная точка и любое количество пробельных символов.
- Для публичных чатов допустимой являются нотации:
* с префиксом в виде любого количества пробельных символов + имени бота + любое количество пробельных символов +
опциональньная запятая + любое количество пробельных символов. После команды опциональная точка и любое
количество пробельных символов.
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + команда + опциональная точка и любое количество пробельных символов.
Ответ на эту фразу - слово "HALP!!!11".
* kde или кде
- Для приватных и публичных чатов допустимой является нотация:
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + команда + опциональная точка и любое количество пробельных символов.
Ответ на эту фразу - одно произвольное предложение из массива ответов на эту фразу.
* roll или dice или кости
- Для приватных и публичных чатов допустимой является нотация:
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + команда + опциональная точка и любое количество пробельных символов.
Ответ на эту фразу - "На первой кости выпало M, а на второй — N.", где M и N произвольные целые числа от 1 до 6
включительно.
* ver или version или версия
- Для приватных и публичных чатов допустимой является нотация:
* символ команды (по-умолчанию - восклицательный знак, задаётся в настройках модуля, отвечающего за конкретны чат-
протокол) + команда + опциональная точка и любое количество пробельных символов.
Ответ на эту фразу - номер версии ПО.
* кто все эти люди?
- Для приватных и публичных чатов допустимой является нотация:
* опциональный префикс 3-х вариаций с одним или более пробельных символов для разделения слов
* вот скажи мне
* скажи мне
* скажи
за которым следует опциональный ник бота с любым количеством пробельных символов, опциональной запятой, любым
количеством пробельных символов. Собственно команда, в которой между словами используется один и более пробельный
символ. Опциональный пробельный символ, любое количество, опциональная запятая, буква "а", опциональный
пробельный символ, любое количество. Вопросительный знак. Опциональный пробельный символ, любое количество.
Ответ на эту фразу
* для приватных чатов: Какие "люди"? Мы здесь вдвоём, только ты и я.
* для публичных чатов: Кто здесь?
* кто я?
- Для приватных и публичных чатов допустимой является нотация:
* опциональный префикс 3-х вариаций с одним или более пробельных символов для разделения слов
* вот скажи мне
* скажи мне
* скажи
за которым следует опциональный ник бота с любым количеством пробельных символов, опциональной запятой, любым
количеством пробельных символов. Собственно команда, в которой между словами используется один и более пробельный
символ. Опциональный пробельный символ, любое количество, опциональная запятая, буква "а", опциональный
пробельный символ, любое количество. Вопросительный знак. Опциональный пробельный символ, любое количество.
Ответ на эту фразу - "Где?", без кавычек.
* кто здесь? или кто тут?
- Для приватных и публичных чатов допустимой является нотация:
* опциональный префикс 3-х вариаций с одним или более пробельных символов для разделения слов
* вот скажи мне
* скажи мне
* скажи
за которым следует опциональный ник бота с любым количеством пробельных символов, опциональной запятой, любым
количеством пробельных символов. Собственно команда, в которой между словами используется один и более пробельный
символ. Опциональный пробельный символ, любое количество, опциональная запятая, буква "а", опциональный
пробельный символ, любое количество. Вопросительный знак. Опциональный пробельный символ, любое количество.
Ответ на эту фразу
* для приватных чатов: Ты да я, да мы с тобой.
* для публичных чатов: Здесь все: Никита, Стас, Гена, Турбо и Дюша Метёлкин.

39
README
View File

@@ -1,19 +1,18 @@
aleesa-craniac
------------------------------------------------------------------------------
Бредогенератор, основанный на цепях Маркова. Попутно сохраняет состояние цепей
в sqlite-базу. Собственно, является "мозгом" aleesa bot-а.
-----------------------------------------------------------------------------------------------------------------------
Бредогенератор, основанный на цепях Маркова. Попутно сохраняет состояние цепей в sqlite-базу. Собственно, является
"мозгом" aleesa bot-а.
Механика работы
------------------------------------------------------------------------------
Бредогенератор подписан на redis-канал craniac. В этот канал пишет другой
демоночек - aleesa-misc. Причём, особенность такова, что если aleesa-misc не
распознала фразу как команду для другого модуля, то по-умолчанию такая фраза
оправляется в канал craniac.
-----------------------------------------------------------------------------------------------------------------------
Бредогенератор подписан на redis-канал craniac. В этот канал пишет другой демоночек - aleesa-misc. Причём, особенность
такова, что если aleesa-misc не распознала фразу как команду для другого модуля, то по-умолчанию такая фраза
оправляется в канал craniac, то есть сюда, в "мозги".
У бредогенератора есть 2 типа входящих сообщений - ключевые фразы, на которые
у него есть готовые ответы и остальные, для которых ему надо решить нужен ли
ответ и по-необходимости сгенерировать его.
У бредогенератора есть 2 типа входящих сообщений - ключевые фразы, на которые у него есть готовые (статические) ответы
и остальные, для которых ему надо решить нужен ли ответ и по-необходимости сгенерировать его, используя данные в цепях
Маркова.
Ответ направляется в redis-канал, указанный в поле plugin входящего сообщения.
@@ -21,15 +20,13 @@ aleesa-craniac
Как это запустить?
------------------------------------------------------------------------------
Понадобится perl, cpanm и local::lib, а также несколько разных devel-пакетов
для разных библиотек. Как правило, это находится методом тыка, но точно
понадобятся sqlite-devel, bdb-devel (или db-devel), hiredis-devel. Кроме того,
понадобятся development tools - gcc, gcc-g++, perl-devel, make, cmake и так
далее.
-----------------------------------------------------------------------------------------------------------------------
Понадобится perl, cpanm и local::lib, а также несколько разных devel-пакетов для разных библиотек. Как правило, это
находится методом тыка, но точно понадобятся sqlite-devel, bdb-devel (или db-devel), hiredis-devel. Кроме того,
понадобятся development tools - gcc, gcc-g++, perl-devel, make, cmake и так далее.
В каталоге с приложением под целевым пользователем запускаем bash bootstrap.sh
Ждём с надеждой, что оно не обломится в пути.
В каталоге с приложением под целевым пользователем запускаем bash bootstrap.sh Ждём с надеждой, что оно не обломится в
пути.
Если всё хорошо, то после запуска redis-а, создания data/config.json из
data/config_sample.json, можно запускать и само приложение.
Если всё хорошо, то после запуска redis-а, создания data/config.json из data/config_sample.json, можно запускать и само
приложение.

View File

@@ -142,96 +142,125 @@ my $parse_message = sub {
my $reply;
# Если $m->{misc}->{answer} не существует, то проставим его как 1, предполагаем, что по-умолчанию ответ от нас
# всё-таки ожидают. Уточним ниже, по содержимому фразы и по режиму беседы (private или public).
# всё-таки ожидают. Если что - уточним ниже.
if (defined $m->{misc}) {
unless (defined $m->{misc}->{answer}) {
$m->{misc}->{answer} = 1;
}
unless (defined $m->{misc}->{csign}) {
$m->{misc}->{csign} = '!';
}
# TODO: не проставлять дефолтный ник!
unless (defined $m->{misc}->{bot_nick}) {
$m->{misc}->{bot_nick} = 'aleesa';
}
} else {
$m->{misc}->{answer} = 1;
$m->{misc}->{csign} = '!';
$m->{misc}->{bot_nick} = 'aleesa';
}
if (defined $m->{misc}->{bot_nick}) {
# Заменим обращение к боту по нику с окружающими запятыми и пробелами на пробел
# Если нам сообщили ник бота, попробуем вымарать его из оригинального текста сообщения, в большинстве случаев он
# нам не интересн.
$phrase =~ s/\s*\,?\s*($m->{misc}->{bot_nick})\s*\,?\s*/ /gui;
}
if ($m->{mode} eq 'private') {
$phrase =~ s/^\s*(вот\s+)?скажи(\s*мне)?\s*//gui;
$phrase =~ s/\s*(,)?\s*а\s*\?$/?/gui;
if ($phrase =~ /^ *кто +все +эти +люди *\?$/ui) {
$reply = 'Какие "люди"? Мы здесь вдвоём, только ты и я.';
} elsif ($phrase =~ /^ *кто +я *\?$/ui) {
$reply = 'Где?';
} elsif ($phrase =~ /^ *кто +(здесь|тут) *\?$/ui) {
$reply = 'Ты да я, да мы с тобой.';
# В ключевых фразах можно обратиться с некоторыми командами к боту по нику, не используя символ команды
if ($m->{message} =~ /^\s*\Q;m->{misc}->{bot_nick}\E\s*;/ui) {
$reply = 'Чего?';
} elsif ($m->{message} =~ /^(\Q$m->{misc}->{csign}\E|\Q$m->{misc}->{bot_nick}\E\s*\,?\s+)pong\.?\s*$/i) {
$reply = 'Wat?';
} elsif ($m->{message} =~ /^(\Q$m->{misc}->{csign}\E|\Q$m->{misc}->{bot_nick}\E\s*\,?\s+)пин(г|х)\.?\s*$/ui) {
$reply = 'Понг.';
} elsif ($m->{message} =~ /^(\Q$m->{misc}->{csign}\E|\Q$m->{misc}->{bot_nick}\E\s*\,?\s+)пон(г|х)\.?\s*$/ui) {
$reply = 'Шта?';
} elsif ($m->{message} =~ /^(\Q$m->{misc}->{csign}\E|\Q$m->{misc}->{bot_nick}\E\s*\,?\s+)(хэлп|halp)\s*$/ui) {
$reply = 'HALP!!!11';
}
} else {
# Если нам не сообщили ник бота, то ищем команды, используя символ команды
if ($m->{message} =~ /^\Q$m->{misc}->{csign}\Epong\.?\s*$/i) {
$reply = 'Wat?';
} elsif ($m->{message} =~ /^\Q$m->{misc}->{csign}\Eпин(г|х)\.?\s*$/ui) {
$reply = 'Понг.';
} elsif ($m->{message} =~ /^\Q$m->{misc}->{csign}\Eпон(г|х)\.?\s*$/ui) {
$reply = 'Шта?';
} elsif ($m->{message} =~ /^\Q$m->{misc}->{csign}\E(хэлп|halp)\s*$/ui) {
$reply = 'HALP!!!11';
# TODO: дописать запрос в webapp, для easter egg-ов, либо делать это на уровне aleesa-misc
if (defined ($reply) && $m->{misc}->{answer}) {
$self->json ($send_to)->notify (
$send_to => {
from => 'craniac',
userid => $userid,
chatid => $chatid,
plugin => $m->{plugin},
message => $reply
}
);
return;
}
} elsif ($m->{mode} eq 'public') {
$phrase =~ s/^\s*(вот\s+)?скажи(\s*мне)?\s*//gui;
$phrase =~ s/\s*(,)?\s*а\s*\?$/?/gui;
if ($phrase =~ /^ *кто +все +эти +люди *\?$/ui) {
$reply = 'Кто здесь?';
} elsif ($phrase =~ /^ *кто +я *?$/ui){
$reply = 'Где?';
} elsif ($phrase =~ /^ *кто +(здесь|тут) *\?$/ui) {
$reply = 'Здесь все: Никита, Стас, Гена, Турбо и Дюша Метёлкин.';
}
if (defined ($reply) && $m->{misc}->{answer}) {
$self->json ($send_to)->notify (
$send_to => {
from => 'craniac',
userid => $userid,
chatid => $chatid,
plugin => $m->{plugin},
message => $reply
}
);
return;
}
}
# Попадаем сюда только если входящая фраза не распознана ранее как ключевая.
if ($m->{misc}->{answer}) {
# Пытаемся что-то генерировать, если фраза длиннее 3-х букв
if (length ($m->{message}) > 3) {
if (brains ($chatid, 1)) {
$reply = $hailo->{$chatid}->learn_reply ($m->{message});
# Поищем в тексте входящего сообщения команды общего плана, с символом команды.
unless (defined $reply) {
if ($m->{message} =~ /^\Q$m->{misc}->{csign}\E(kde|кде)\s*$/ui) {
my @phrases = (
'Нет, я не буду поднимать вам плазму.',
'Повторяйте эту мантру по утрам не менее 5 раз: "Плазма не падает." И, возможно, она перестанет у вас падать.',
'Плазма не падает, она просто выходит отдохнуть.',
'Плазма это не агрегатное состояние, это суперпозиция. Во время работы она находится сразу в жидком, мягком и тёплом состояниях.',
);
# Если из реактора вернулся undef выдаём "общую" фразу из словаря
unless (defined $reply) {
$reply = RandomCommonPhrase ();
$reply = $phrases[irand ($#phrases + 1)];
} elsif ($m->{message} =~ /^\Q$m->{misc}->{csign}\E(coin|монетка)$/ui) {
if (rand (101) < 0.016) {
$reply = 'ребро';
} else {
if (irand (2) == 0) {
if (irand (2) == 0) {
$reply = 'орёл';
} else {
$reply = 'аверс';
}
} else {
# Если из реактора вернулась пустота выдаём "общую" фразу из словаря
if ($reply eq '') {
$reply = RandomCommonPhrase ();
}
# Если сгенерированная фраза слишком похожа на начальную - выдаём "общую" фразу из словаря
if (fmatch (lc ($m->{message}), lc ($reply))) {
$reply = RandomCommonPhrase ();
if (irand (2) == 0) {
$reply = 'решка';
} else {
$reply = 'реверс';
}
}
}
} elsif ($m->{message} =~ /^\Q$m->{misc}->{csign}\E(roll|dice|кости')$/ui) {
$reply = sprintf 'На первой кости выпало %d, а на второй — %d.', irand (6) + 1, irand (6) + 1;
} elsif ($m->{message} =~ /^\Q$m->{misc}->{csign}\E(ver|version|версия)$/ui) {
$reply = 'Версия: Четыре.Технологическое_превью';
}
}
# У нас уже есть чего ответить, нам попалась известная фраза, на которую одинаковый ответ, независимо от типа
# общения - публичного или приватного.
if (defined $reply) {
if ($m->{misc}->{answer}) {
$self->json ($send_to)->notify (
$send_to => {
from => 'craniac',
userid => $userid,
chatid => $chatid,
plugin => $m->{plugin},
message => $reply
}
);
}
} else {
# Пока что нам нечего ответить, известных фраз не нашлось. Ищем дальше, на сей раз фразы, зависящие от режима
# общения - приватного ли публичного.
if ($m->{mode} eq 'private') {
$phrase =~ s/^\s*(вот\s+)?скажи(\s*мне)?\s*//gui;
$phrase =~ s/\s*(,)?\s*а\s*\?$/?/gui;
if ($phrase =~ /^\s*кто\s+все\s+эти\s+люди\s*\?\s*$/ui) {
$reply = 'Какие "люди"? Мы здесь вдвоём, только ты и я.';
} elsif ($phrase =~ /^\s*кто\s+я\s*\?\s*$/ui) {
$reply = 'Где?';
} elsif ($phrase =~ /^\s*кто\s+(здесь|тут)\s*\?\s*$/ui) {
$reply = 'Ты да я, да мы с тобой.';
}
# TODO: дописать запрос в webapp, для easter egg-ов, либо делать это на уровне aleesa-misc
if (defined ($reply) && $m->{misc}->{answer}) {
$self->json ($send_to)->notify (
$send_to => {
from => 'craniac',
@@ -241,13 +270,76 @@ my $parse_message = sub {
message => $reply
}
);
return;
}
} elsif ($m->{mode} eq 'public') {
$phrase =~ s/^\s*(вот\s+)?скажи(\s*мне)?\s*//gui;
$phrase =~ s/\s*(,)?\s*а\s*\?$/?/gui;
if ($phrase =~ /^\s*кто\s+все\s+эти\s+люди\s*\?\s*$/ui) {
$reply = 'Кто здесь?';
} elsif ($phrase =~ /^\s*кто\s+я\s*?\s*$/ui){
$reply = 'Где?';
} elsif ($phrase =~ /^\s*кто\s+(здесь|тут)\s*\?\s*$/ui) {
$reply = 'Здесь все: Никита, Стас, Гена, Турбо и Дюша Метёлкин.';
}
if (defined ($reply) && $m->{misc}->{answer}) {
$self->json ($send_to)->notify (
$send_to => {
from => 'craniac',
userid => $userid,
chatid => $chatid,
plugin => $m->{plugin},
message => $reply
}
);
return;
}
}
} else {
# пытаемся что-то запоминать, если фраза длиннее 3-х букв
if (length ($m->{message}) > 3) {
if (brains ($chatid, 1)) {
$hailo->{$chatid}->learn ($m->{message});
# Попадаем сюда только если входящая фраза не распознана ранее как ключевая.
if ($m->{misc}->{answer}) {
# Пытаемся что-то генерировать, если фраза длиннее 3-х букв
if (length ($m->{message}) > 3) {
# Lazy brain init
if (brains ($chatid, 1)) {
$reply = $hailo->{$chatid}->learn_reply ($m->{message});
# Если из реактора вернулся undef выдаём "общую" фразу из словаря
unless (defined $reply) {
$reply = RandomCommonPhrase ();
} else {
# Если из реактора вернулась пустота выдаём "общую" фразу из словаря
if ($reply eq '') {
$reply = RandomCommonPhrase ();
}
# Если сгенерированная фраза слишком похожа на начальную - выдаём "общую" фразу из словаря
if (fmatch (lc ($m->{message}), lc ($reply))) {
$reply = RandomCommonPhrase ();
}
}
$self->json ($send_to)->notify (
$send_to => {
from => 'craniac',
userid => $userid,
chatid => $chatid,
plugin => $m->{plugin},
message => $reply
}
);
}
}
} else {
# пытаемся что-то запоминать, если фраза длиннее 3-х букв
if (length ($m->{message}) > 3) {
if (brains ($chatid, 1)) {
$hailo->{$chatid}->learn ($m->{message});
}
}
}
}