Роботы, плагины и скрипты к чату MyChat. Разработка альтернативных клиентов и различных утилит. Технические вопросы по программированию, замечания и предложения по развитию API
noti
Добрый день!

Хочу реализовать следующий функционал:
Пользователь пишет вопрос Элизе в определенной форме, например Ш/К 4811230000694
на что Элиза отвечает "32 ЖЕМЧУЖИНЫ 100г отбеливающ. з/паста"

Вопрос только в том, как организовать "Событие" - обращение к Элизе, которое вызывало бы Процедуру, которая в свою очередь будет обрабатывать вопрос.

Спасибо за помощь!
Аватара пользователя
Алексей Пикуров
Добрый.

Всё достаточно просто. Вам нужно событие OnPrivateMessage и функция скрипт-языка function mGetLastPrivateMessage(iUINFrom, iUINTo: integer): string;

Я написал простой пример с обычным текстовым файлом. Файл выглядит так (одна строка, кодировка ASCII, Win1251):
Код: Выделить всё
Ш/К 4811230000694|32 ЖЕМЧУЖИНЫ 100г отбеливающ. з/паста

Т.е. сначала идёт код (в UpperCase), потом знак | и потом уже текст, который вы будете выводить. Но это так, для примера. Если в файле будут десятки тысяч строк, такой скрипт будет не эффективен, конечно. Но для примера сойдёт.
scriptexample.png
Пример скрипта для взаимодействия со встроенным роботом Elisa в чате MyChat

Текст скрипта:
Код: Выделить всё
const
  sDataFile = 'c:\data\base.txt';
var
  iUINFrom, iUINTo, iCount, i: integer;
  sMsg, sData: string;
begin
  // получаем последнее сказанное приватное сообщение
  sMsg := UpperCase(mGetLastPrivateMessage(iUINFrom, iUINTo));
 
    if iUINTo=0 then begin // если получатель - Elisa (UIN=0)
      // смотрим, сколько в текстовом файле строк
      iCount := GetTextFileLinesCount(sDataFile);
     
        // идём по всему файлу в надежде встретить нужную нам строку
        for i := 1 to iCount do begin
          LoadLineFromFile(sDataFile, i, sData);
         
            // если нашли
            if pos(sMsg+'|', sData) = 1 then begin
              delete(sData, 1, length(sMsg)+1);
              // удаляем последнее приватное сообщение
              mModifyLastPrivateMessage(iUINFrom, iUINTo, '');
              // и отправляем пользователю новое сообщение от имени робота Elisa
              mSendPrivateMessage(iUINFrom, sData);
            end; 
        end;
    end;
end.

В примере я предположил, что текстовый файл, откуда вы будете доставать данные, лежит в c:\data\base.txt. В самом скрипте, когда сервер видит, что сообщение пришло роботу (UIN получателя равен нулю), обрабатывается текст запроса, и если в текстовом файле есть нужные данные, то сообщение, которое пришло к Элизе - удаляется и формируется нужный ответ. В приват придёт что-то вроде этого:
elisaresponse.png
Ответ робота на запрос
elisaresponse.png (9.23 КБ) Просмотров: 5957
Аватара пользователя
Алексей Пикуров
Получилось ли реализовать желаемое?
noti
Спасибо! То что нужно!
Главное теперь понял как "читать" сообщения к Элизе!!
Аватара пользователя
Алексей Пикуров
В новой версии MyChat скриптовая функция mSendPrivateMessage была изменена, пожалуйста, учтите это и переделайте свои скрипты.

Справка
Аватара пользователя
Vyacheslav34
Парни, ну ведь круто !!
Так Элиза скоро торговать научится , осталось только сканер зацепить.
Просто офигеть какой гибкиий чат придумали.
Надо все темы ветки перелопатить столько интересного!
Большое человеческое спасибо !
Аватара пользователя
Алексей Пикуров
Пожалуйста. Пишите скрипты, спрашивайте, всегда поможем.
Аватара пользователя
Алексей Пикуров
Свежий вариант, пример для организации чат-бота.
СергейДигтярь
Здравствуйте. Подобный сценарий общения с ботом реализовать получилось, спасибо. Но вот все никак не можем понять, каким образом реализовать обращение к боту, чтобы поиск производился по ключевому слову с выводом всех совпадающих результатов.
Например, есть файл с следующими строками:
Отдел приема граждан;123456
Отдел юристов;7890123
Нужно, чтобы при обращении к боту по слову "отдел", он в ответ выдавал эти две доступные в файле строки. А при вводе "юр" в ответ мы получали "Отдел юристов 7890123".
Заранее, спасибо вам за вашу помощь.
Аватара пользователя
Алексей Пикуров
Читаете файл в память, обрабатываете его в цикле, функцией Fetch отрезая построчно до CRLF, анализ делаете функцией Pos от AnsiLowerCase строки, чтобы не различать регистр букв.
СергейДигтярь
Благодарю за подсказку, подправил скрипт, ищет по списку и находит. Но, в результат возвращает первое попавшее похожее значение из строки, вместо нескольких значений в разных строках, не пойму, как построить цикл? Прошу не пинать, потому как только учусь. Подскажите, пожалуйста. Вот мой пример скрипта. Спасибо

Код: Выделить всё

const
  Base = 'd:\valeratel.txt';
  My_Bot = 0;
 
function OnPrivateMessage(iCID, iUIN, iUINTo, iMsgType: integer; sMsg: string): boolean;
var
  sCmd, sSt, sData, s: string;
  sReplyText: string;
  x: integer;
 
 
begin
  result := true;
 
    if (iUINTo = My_Bot) and (iMsgType in [0,1]) then begin
      sCmd  := AnsiLowerCase(mConvertMsgToPlainText(sMsg, iMsgType));
      sData := LoadTextFromFile(Base, 1);
      x     := pos(sCmd , sData);
   
        if x <> 0 then begin
          s := copy(sData, x, PosEx(CRLF, sData, x + 1) - x);
          Fetch(s, ';');
          mSendPrivateMessage(My_Bot, iUIN, s, 1, true);
          result := false;
        end;
    end;   
end;

begin

end.
Аватара пользователя
Алексей Пикуров
Код: Выделить всё
function OnPrivateMessage(iCID, iUIN, iUINTo, iMsgType: integer; sMsg: string): boolean;
var
  sCmd, sData, s: string;
  bFlag: boolean;
begin
  bFlag := true;
 
    if (iUINTo = My_Bot) and (iMsgType in [0,1]) then begin
      sCmd  := AnsiLowerCase(mConvertMsgToPlainText(sMsg, iMsgType));
      sData := LoadTextFromFile(Base, 1);

        while length(sData) > 0 do begin // перебираем все строки
          s := Fetch(sData, CRLF); // откусываем строку
 
            if pos(sCmd, AnsiLowerCase(s)) <> 0 then begin // если подстрока есть в строке
              mSendPrivateMessage(My_Bot, iUIN, s, 1, true); // отправляем строку юзеру
              bFlag := false; // подавляем вопрос юзера, выводим только ответ бота
            end; 
        end;
    end;   

  result := bFlag;
end;
СергейДигтярь
Громаднейшее спасибо! Работает, как доктор прописал! [smilie=good.gif] Принцип построения понятен, все куда проще!