Проект Small Basic #8 "Простой чат-бот"

Задача

Написать примитивный чат-бот, который умеет отвечать на приветствие, спрашивать, как дела, ссылать человека с вопросом в гугл, различать слова хорошего настроения и плохого, в случае непонятного для него текста, выводит случайную цитату, спарсенную в Интернете.

Как будет выглядеть результат (скрин переписки с ботом)

Алгоритм работы

Ход работы

1. Накидаем наборы со словами-триггерами, на которые бот будет реагировать. 

Наборы слов у нас в виде строки. Нам так это делать удобнее, чем накидывать лично в массивы.
notEnd = "true"

' Набор  слов-приветствий
greetings = "привет,здравствуйте,здоров,здравствуй,хай,дороу,дарова,здарова,прив"
' Набор  общих вопросов
personQuestions = "дела,делаешь,делаеш,жизнь,делаете,чё"
' Набор  вопросов, в ответ на которые нужно ссылать в гугл
askQuestions = "помоги,можешь,можете,помогите,найти,как,сколько,каким,почему,зачем,что "
' Набор  слов хорошего настроения
goodMood = "хороший,взаимно,хорошо,класс,классно,здорово,супер,чудесно,приятно,приятный,замечательно,отлично,спасибо,великолепно"
' Набор слов плохого настроения
badMood = "жуть,жуткий,плохой,плохо,грустно,печаль,пичаль,разочарование,жаль,печально,грусть,беда,горе,тупой,блин"
' Набор слов, которые связаны с тем, что пользователь намекает на чатботовость
interesting = "чат-бот,чатбот,чатботом,чат-ботом,чатботу,боту,чатбота,бот,бота,машина,компьютер,чат,неживой,робот,роботом,робота,роботы,роботу"

Обратите внимание, что слова мы перечисляем через запятую, чтобы было легко потом их распределять по массивам

2. Теперь эти наборы слов-триггеров нужно программно разбить по словам на массивы.

interesting = "чат-бот,чатбот,чатботом,чат-ботом,чатботу,боту,чатбота,бот,бота,машина,компьютер,чат,неживой,робот,роботом,робота,роботы,роботу"

'======= Greetings array =========
index = 1

' Пока в наборе greetings есть символы, будем добывать слова и закидывать их в массив
While greetings <> ""
  ' Сначала находим запятую
  commaIndex = Text.GetIndexOf(greetings,",")

  ' Если запятая найдена
  If commaIndex <> 0 Then
    ' Добываем текст до запятой
    word = Text.GetSubText(greetings,1,commaIndex-1)
    ' Вырезаем это слово с запятой из набора слов-триггеров
    greetings = Text.GetSubTextToEnd(greetings,commaIndex+1)
    ' Добытое слово закидываем в массив с приветственными словами
    greetingsArray[index] = word

  ' Если запятой не найдено (то есть, это последнее слово)
  Else'
    word = greetings
    ' Очищаем набор
    greetings = ""
    greetingsArray[index] = word
  EndIf
  index = index+1
EndWhile

3. Так же сделаем и для остальных наборов. Например, вот так будет выглядеть разбивка строки на массив из личных вопросов.

  index = index+1
EndWhile

'======= personQuestions array =========
index = 1
While personQuestions <> ""
  commaIndex = Text.GetIndexOf(personQuestions,",")
  If commaIndex <> 0 Then
    word = Text.GetSubText(personQuestions,1,commaIndex-1)
    personQuestions = Text.GetSubTextToEnd(personQuestions,commaIndex+1)
    personQuestionsArray[index] = word
  Else'
    word = personQuestions
    personQuestions = ""
    personQuestionsArray[index] = word
  EndIf
  index = index+1
EndWhile

4. Теперь перейдём к описанию работы бота и началу диалога.

TextWindow.ForegroundColor = "Gray"
TextWindow.WriteLine("*** Это простой чат-бот, пишите небольшими предложениями, удачи! ")
TextWindow.WriteLine("*** Пишите без знаков препинания, пожалуйста =) ")
TextWindow.ForegroundColor = "Green"
TextWindow.CursorTop = 5
TextWindow.WriteLine("Привет!")

5. Дальше начинается цикл чата. 

Добавим ответ пользователя на сообщение бота:

TextWindow.WriteLine("Привет!")
While notEnd = "true"
  TextWindow.ForegroundColor = "Yellow"
  answer = Text.ConvertToLowerCase(TextWindow.Read())
  TextWindow.ForegroundColor = "Green"
EndWhile

6. Первое, что мы сделаем в чате – это разобьём ответ пользователя на слова (по пробелам). 

Сделаем это так же, как мы и разбивали наборы слов-триггеров. Что поменяется – так это то, что из последнего слова в наборе мы будем удалять символы "?!.)".

  TextWindow.ForegroundColor = "Green"
  index = 1
  While answer <> ""
    spaceIndex = Text.GetIndexOf(answer," ")
    If spaceIndex <> 0 Then
      word = Text.GetSubText(answer,1,spaceIndex-1)
      answer = Text.GetSubTextToEnd(answer,spaceIndex+1)
      answerArray[index] = word
    Else'
      word = answer
      If Text.EndsWith(word,"?") Or Text.EndsWith(word,"!") Or Text.EndsWith(word,".") Or Text.EndsWith(word,")") Then
        length = Text.GetLength(word)
        word = Text.GetSubText(word,1,length-1)
      EndIf
      answer = ""
      answerArray[index] = word
    EndIf
    index = index+1
  EndWhile
EndWhile

7. Добыли массив из введённых слов. Теперь нужно проверить наличие этих слов в массивах со словами-триггерами. Если они находятся в таком массиве, изменяем определённый тип ответа на true:

    index = index+1
  EndWhile

  For i=1 To Array.GetItemCount(answerArray)
    If Array.ContainsValue(greetingsArray,answerArray[i]) Then
      greetingResponse = "true"
    ElseIf Array.ContainsValue(personQuestionsArray,answerArray[i]) Then
      personQuestionsResponse = "true"
    ElseIf Array.ContainsValue(askQuestionsArray,answerArray[i]) Then
      askQuestionsResponse = "true"
    ElseIf Array.ContainsValue(goodMoodArray,answerArray[i]) Then
      goodMoodResponse = "true"
    ElseIf Array.ContainsValue(badMoodArray,answerArray[i]) Then
      badMoodResponse = "true"
    ElseIf Array.ContainsValue(interestingArray,answerArray[i]) Then
      interestingResponse = "true"
    EndIf
  EndFor
EndWhile

8. Самое интересное – здесь мы проверяем, какой тип ответа определил бот и в зависимости от этого выводим тот или иной ответ:

    EndIf
  EndFor

  If greetingResponse = "true" Then
    TextWindow.WriteLine("Рад с тобой познакомиться!")
    TextWindow.WriteLine("Что делаешь?")
  ElseIf personQuestionsResponse = "true" Then
    TextWindow.WriteLine("Спасибо! Вот, с тобой переписываюсь))")
    TextWindow.WriteLine("Как день прошёл?")
  ElseIf askQuestionsResponse = "true" Then
    TextWindow.WriteLine("Гугл тебе в помощь. Я умею только цитатами говорить")
  ElseIf goodMoodResponse = "true" Then
    TextWindow.WriteLine("Это чудесно! Очень рад.")
    TextWindow.WriteLine("Расскажи мне что-то ещё.")
  ElseIf badMoodResponse = "true" Then
    TextWindow.WriteLine("Сочувствую...")
  ElseIf interestingResponse = "true" Then
    TextWindow.WriteLine("Тебя удивляет, что ты общаешься с роботом? Ничего, мне не впервую, привыкай))")
  Else
    TextWindow.WriteLine("Ты дивный юзер, но твой лепет бессмыслен для меня, сорян...")
  EndIf
EndWhile

9. В начале цикла чата нужно обнулять тип ответа, потому что пользователь введёт новое сообщение.

While notEnd = "true"
  answerArray = ""
  greetingResponse = "false"
  personQuestionsResponse = "false"
  askQuestionsResponse = "false"
  goodMoodResponse = "false"
  badMoodResponse = "false"
  interestingResponse = "false"
  TextWindow.ForegroundColor = "Yellow"

10. Давайте сделаем поинтереснее ответ бота, если среди фразы пользователя не было найдено ни одного слова-триггера. 

Пусть бот полезет в интернет на сайт со случайной цитатой, спарсит веб-страницу и добудет оттуда текст этой фразы:
    TextWindow.WriteLine("Тебя удивляет, что ты общаешься с роботом? Ничего, мне не впервую, привыкай))")
  Else
    TextWindow.WriteLine("Ты дивный юзер, но твой лепет бессмыслен для меня, сорян...")
    ' Получить содержимое веб-сайта https://quote-citation.com/random
    randomQuotation = Network.GetWebPageContents("https://quote-citation.com/random")
    ' Найти на странице, где находится блок с цитатой (у неё есть подпись "quote-text")
    indexQuot = Text.GetIndexOf(randomQuotation,"quote-text")
    ' Отступить от этого места 37 символов и оставить только текст после этого символа
    quotationPart = Text.GetSubTextToEnd(randomQuotation,indexQuot+37)
    ' Найти место, где заканчивается цитата
    indexQuot2 = Text.GetIndexOf(quotationPart,"</p>")
    ' Обрезать текст до этого места
    quotationPart2 = Text.GetSubText(quotationPart,1,indexQuot2-1)
    TextWindow.WriteLine(quotationPart2)
  EndIf
EndWhile

11. Для иллюстрации того, как бот парсит веб-страницу, рассмотрим на примере:

11.1. Перейдите на сайт https://quote-citation.com/random
11.2. Нажмите CTRL+U – так вы можете посмотреть исходный код страницы
11.3. Осуществите поиск на странице (CTRL+F) на наличие текста "quote-text".У меня, например, сейчас такая цитата:
 <div class="quote-text" id="quote-text-7801"><p>Чтобы зарабатывать деньги, надо уметь их тратить.</p>
11.4. Бот отступает 37 символов от quote-text, доходит до </p> и этот текст возвращает как ответ юзеру.

Задания

Задание 1**. Добавьте ещё один набор со словами-триггерами прощания. Если бот встречает такие слова в сообщении пользователя, он прощается, ждёт 1 секунду и выключает программу.

Задание 2***. Сейчас парсер несовершенен – он может обрезать от цитаты лишнюю букву-две. Подумайте, что следует ещё обрезать текст слева, чтобы это было не по отступу в 37 символов, а по другому принципу.

Задание 3**. Добавьте в чат-бот возможность калькулятора: если пользователь пишет слова "посчитай" или "калькулятор", то бот предлагает ввести два числа, выбрать операцию. После этого бот выводит результат на экран и продолжает общаться с пользователем.

Задание 4****. Добавьте чатботу возожность отвечать на вопрос: "Сколько подписчиков у @nickzames?". Чатбот должен добыть из инстаграма эту цифру и вывести на экран пользователю.

Задание 5*****. Добавьте чатботу возожность отвечать на вопрос: "Сколько градусов будет 22 декабря?". Чатбот должен добыть с сайта SINOPTIC температуру и вывести на экран пользователю.
Адрес сайта и пример запроса: https://sinoptik.ua/погода-черноморск/2019-12-22

Комментарии