программульки в персональной песочнице

delta — Сверхъестественный интеллект или ёщё одна программа автоответчик.

© Dmitry Bodyonov (aka dimkazavr), 2005.
# python

Говорящий робот delta – демо-версия.

Введите свой текст в поле и нажмите кнопку отправки справа (или [ENTER]) чтобы получить ответ робота.

Описание

delta – программа автоответчик. Может использоваться как самостоятельная программа (в том числе, как сетевой демон в linux/*nix системах), либо как часть другой программы на python.

В delta используется простой контекстно-независимый алгоритм (без сохранения контекста разговора), выбирающий ответ соответствующий шаблону. В шаблонах возможно использовать регулярные выражения, ответ выбирается случайно из списка возможных для данного шаблона. Ответы могут содержать макроопределения, которые рекурсивно раскрываются при формировании результата.

Формат словарей

Словари хранятся в формате xml, возможна загрузка нескольких словарей. Декларация типа документа (DTD) для словаря имеет вид:

<!DOCTYPE dictionary [

       <!-- Словарь состоит из необязательного описания и набора записей -->
       <!ELEMENT dictionary (description?, entry*) >

       <!-- Обязательно указание версии формата словаря в виде атрибуда тега-->
       <!ATTLIST dictionary version CDATA #REQUIRED>

       <!-- В описании может быть имя автора, дата и коментарии -->
       <!ELEMENT description (author?, date?, comments?)>
       <!ELEMENT author (#PCDATA)>
       <!ELEMENT date (#PCDATA)>
       <!ELEMENT comments (#PCDATA)>

       <!-- Каждая запись словаря состоит из списков шаблонов и ответов -->
       <!ELEMENT entry (patterns, answers)>

       <!-- Для записи можно указать приоритет -->
       <!ATTLIST entry priority CDATA #IMPLIED>

       <!-- Список шаблонов состоит из шаблонов -->
       <!ELEMENT patterns (pattern+)>

       <!-- Шаблон -- это любые текстовые данные -->
       <!ELEMENT pattern (#PCDATA)>

       <!-- Шаблон может иметь атрибут типа --> 
       <!ATTLIST pattern type (macro|exc|asis) #IMPLIED>

       <! Список ответов состоит из ответов -->
       <!ELEMENT answers (answer+)>

       <!-- Ответ -- это любые текстовые данные -->
       <!ELEMENT answer (#PCDATA)>

]>

Пример простейшего словаря:

<?xml version = '1.0'?>
    <dictionary version="1.0">

        <entry>

            <patterns>
                <pattern>hello</pattern>
                <pattern>good morning</pattern>
            </patterns>

            <answers>
                <answer>hi!</answer>
                <answer>hello</answer>
            </answers>

        </entry>

</dictionary>

В описании шаблонов используются регулярные выражения, потому часть символов представляет собой специальные последовательности, например '.', '*', '?', '+', '^', '$', '\b', '\s', '\w' ... (полный список специальных символов и их описание приведен в Python Library Reference). Если необходимо использовать специальные символы в самой строке шаблона их необходимо отделить символом '\', или же указать атрибут type="asis".

Примеры шаблонов:

.......
<pattern>кто здесь\?</pattern>
<pattern>я люблю .*</pattern>
<pattern>^да$</pattern>
.......

Если для шаблона указан тип 'exc', то данный шаблон будет отнесен в список шаблонов исключений для данной записи.

При поиске варианта ответа будет выбрана запись, имеющая наибольший приоритет, а также имеющая совпадение хотя бы одного шаблона со входной строкой и не имеющая совпадений с шаблонами из списка исключений. Более высокий приоритет имеют записи, определения которых в xml файле идут раньше. Также возможно явное указание приритета с помощью атрибута priority в теге entry.

Ответ выбирается случайно из списка возможных ответов для выбранной записи. Строка ответа может содержать специальные макроопределения, которые раскрываются рекурсивно. Имя макроопределения начинается и заканчивается символом '$'. Если необходимо использовать символ '$' в самой строке, следует удвоить этот символ – '$$'.

Макроопределения $1$, $2$ и т.д. заменяются на части входной строки, соответствующие выделенным группам в регулярном выражении шаблона. Например

....
<pattern>я хочу(.*)</pattern>
....
<answer>я не хочу $1$</answer>
....

Для остальных макроопределений производится поиск в основном словаре подходящей записи. Такая запись должна содержать шаблон вида

....
<pattern>\$macroname\$</pattern>
....

Можно не использовать символы '\$' по краям строки, а указать тип шаблона, type="macro".

Описание файлов

delta.py
основной модуль, реализация 'движка' автоответчика. Соджержит набор классов для организации словарей и работы с ними. Главным классом, реализующим собственно интерфейс движка является класс delta. У него доступны следующие методы:
LoadDictionary (FILENAME)
Загрузка словаря из файла. Метод возвращает количество загруженных записей в случае успеха, в случае неудачи возбуждает исключение. Регулярные выражения для шаблонов для записей во время загрузки компилируются чтобы уменьшить время поиска ответов, соответственно это сказывается на времени загрузки каждого словаря.
Parse(INPUT)
Генерация ответа на исходную строку INPUT. Строка INPUT должна быть типа unicode.
SetDebugMode (mode)
Установка режима отладки. При значениях больше 0, сообщения будут выводится на стандартный поток вывода.

Пример использования модуля:

# подключение модуля
import delta

# создание экземпляра движка
E = delta.delta()

# загрузка словаря     
E.LoadDictionary ("dictionary.xml")

# печать ответа на строку 'hello'
print E.Parse("hello")
commander-delta.py

программа с комманднострочным интерфейсом для delta.

Имеет следующий формат вызова:

commander-delta.py  [-d] [-p] [-l LNAG] [dictrionary 1] ...

Опция '-p' включает повторный вывод исходных строк вместе с результатом. Опция '-d' увеличивает степень подробности сообщений отладки, можно указать несколько опций '-d', тогда уровень будет выше. Опция '-l' задает локаль, в которой должна работать программа. Для корректной обработки строк необходимо правильное зачение локали, а также указание кодировки, используемой для входных и выходных файлов. Если опция не задана, то будет использовано значение переменной окружения $LANG.

Пример работы программы:

dima@fedik> ./commander-delta.py      
=====================================================
=      Command line interface for the delta.       =
=====================================================
(c) Dmitry Bodyonov 2005 bodyonov<>karelia.ru       
=====================================================

[*] Applying locale settings (ru_RU.KOI8-R)
[*] Creating delta instance
[*] Loading dictionary ( dictionary.xml )
Done. Have fun! :)

> hello
ну привет
tk-delta.py

программа с графическим интерфейсом на основе Tk для delta.

(На некоторых системах (RH9) наблюдались проблемы с выводом русских символов. Возможно это является результатом недостаточного опыта или количества серого вещества у меня, однако на большинстве проверенных систем (SuSE9.1, SuSE9.3, WinXP) таких проблем нет.)

server-delta.py

Простой tcp сервер для delta.

Так как время загрузки большого словаря может быть значительным (до нескольких секунд), то это может стать проблемой в случае когда нужно выполнять серию независымых запросов. Логичным вариантом выглядит запуск единого сервера, однажды загрузившего словари, и принимающего запросы от клиентов, в том числе и находящихся на других хостах.

Параметры вызова сервера:

server-delta.py [-p PORT] [-a ADDR] [-d] [-l LANG] [ dictionary 1 ] ...

Возможно указать порт на котором должен слушать сервер (по умолчанию 17777), а также адрес к которому необходимо привязаться (по умолчанию 127.0.0.1) Опция '-d' увеличивает уровень отладочных сообщений.

Сервер реализует простейшую итеративную модель обработки – в каждый момент времени может обслуживаться не более одного клиента. В текущей версии сервер не уходит в фон при запуске и не ограничивает время общения с клиентом.

Протокол общения с сервером имеет следующий формат:

  1. клиент устанавливает соединение
  2. клиентом посылается исходная строка в формате UTF8
  3. сервером посылается строка в ответ в формате UTF8
  4. соединение закрывается сервером
client-delta.py

клиент для tcp сервера delta.

Все строки пользователя клиент отправляет на сервер и печатает полученный от него результат.

Формат вызова клиента:

client-delta.py [-a ADDR] [-p PORT] [-l LANG] [-r] [-s TEXT] [-q]

ADDR и PORT определяют адрес и порт сервера, по умолчанию используются значения 127.0.0.1:17777. Опиция '-l' позволяет указать локаль и кодировку, если опция пропущена, то используется переменная окружения $LANG. Опция '-r' включает режим печати исходных строк. Опция '-q' выключает вывод сообщений диагностики. Если задана опция '-s', то ее параметр будет использован как строка введенная пользователем, после обработки этого запроса клиент закончит работу.

Пример работы клиента:

dima@fedik> ./client-delta.py
=====================================================
=          Client for the delta server.            =
=====================================================
(c) Dmitry Bodyonov 2005 bodyonov<>karelia.ru       
=====================================================

[*] Creating encoder for your locale ( ru_RU.KOI8-R )
Done. Have fun! :)

> hello
hello

> how are you?
[error]:  Connection to 127.0.0.1:17777 failed
dictionary-russian.xml, dictionary-mat.xml
Мои словари, составленные на основе разговоров по icq.

Демо версия

Желающие проверить работу автоответчика могут пообщаться с роботом по icq #251019635 (если он будет online, состояние в данный момент: icq user status). В качестве icq клиента используется centericq, delta вызывается в качестве "внешного действия" следующим образом:

dima@research> cat ~/.centericq/external
%action Answering machine
event msg
proto all
status all
options stdout stdin

%exec
#!/bin/bash
msg=`cat`
/home/dima/Work/Projects/delta/release/client-delta.py -q -r -s "$msg" 2>/dev/null

Запуск программы

Для запуска программы требуется наличие python версии не ниже 2.2, а также наличие модуля xml.

Благодарности

За помощь в составлении словарей, а также за тестирование робота выражается благодарность Заморской Наталье (Belka UIN=47367313) и Романчуку Алексею (Mad_Dog).

Ссылки

Ослярик живёт здесь! [d!ë]