Хочу описать процесс создания приложения, которое работает с OpenAI API. Идея приложения возникла из потребности улучшить мой английский язык. Как говорится, если у вас есть молоток, то все проблемы выглядят как гвозди. Так как я программист, я решил написать Искусственный Интеллект, который будет заменять учителя английского языка.

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

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

Я, конечно, могу выполнить все эти задачи, но создание такого сервиса будет достаточно долгим и необходимы значительные инвестиции. А сделать это на коленке и потерять свое время, и не иметь возможности составить конкуренцию с аналогичными стартапами из США, которые имеют достаточные средства на рекламу и развитие, неинтересно.

Вернемся к тонкостям реализации данного приложения. Для того чтобы получить список основных слов по теме, нужно выполнять запрос "completions" к OpenAI API. Этот запрос возвращает логическое завершение текста, который вы ему передадите, например, список основных слов по теме урока.

В итоге, методом проб и ошибок у меня получился запрос, который посылает программа, он выглядит следующим образом:

Give list of words linked with the subject "_TOPIC_". Words should comma separated. Only words.

Где _TOPIC_ - тема урока с ИИ-учителем. Результатом работы этого запроса будет список слов, разделенных запятой, по нужной вам теме.

Далее по логике приложения необходимо было дать объяснение словам, которые не знает ученик. Получился следующий запрос:

Give answer what is "_WORD_" from the field "_TOPIC_".

Где _WORD_ - слово, которое требует объяснения, _TOPIC_ - тема урока. В ответ вы получите 1-2 предложения, объясняющие данное слово.

Для наглядности, необходимо сгенерировать примеры использования данного слова. У меня получились следующие два запроса:

Give sentence with word "_WORD_" in field "_TOPIC_".

Give rude sentence with word "_WORD_" in field "_TOPIC_".

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

Далее приложение должно вступить в диалог с учащимся. Один из самых простых способов - это использовать список слов по теме урока и задать вопрос, используя его. У меня получился следующий запрос к OpenAI API:

Give _QUESTION_TYPE_. About "_TOPIC_". Use word "_WORD_". Do not use word "_TOPIC_".

Где _QUESTION_TYPE_ - тип вопроса, который выбирается случайным образом из списка:

  1. Yes/No question

  2. Wh-question

  3. Choice question

  4. Open-ended question

  5. Hypothetical question

  6. Leading question

  7. Rhetorical question

  8. Funnel question

  9. Probing question

  10. Clarifying question

  11. Follow-up question

  12. Forced-choice question

  13. Matching question

  14. Categorical question

  15. Comparison question

  16. Rude question

  17. Polite question

Что позволяет генерировать всегда разные вопросы даже при многократном прохождении урока по одной и той же теме.

При том в этом запросе я добавил в конец "Do not use word "_TOPIC_", чтобы в каждом вопросе от учителя не было слова с упоминанием темы урока, а то все предложения будут одинаковыми. И выглядит это очень не естественно.

Далее стоит задача определить, есть ли ошибки в ответе ученика. Для этого у OpenAI API есть запрос "edits". Он позволяет взять кусок текста и изменить в него. Там два параметра: исходный текст и то, что с ним надо сделать. В итоге, я, вызывая эту функцию, передавал текст ответа ученика и следующую строку:

Fix grammar and spelling.

На выходе я получал строку с исправленным текстом. Если она не совпадала с тем что писал ученик, то я считал, что он ошибся, и выводил исправленный вариант.

В случае, когда ученик игнорирует вопрос ИИ-учителя и пишет в ответ свой вопрос, или отвечая на него, добавляет еще и свой, то я через OpenAI API "completions" генерирую ему ответ такой строкой:

Give _SENTENCE_TYPE_ answer on text: _STUDENT_QUESTION_.

Где _STUDENT_QUESTION_ - текст с вопросом учащегося, а _SENTENCE_TYPE_ - тип утвердительного предложения который выбирается случайным образом из следующего списка:

  1. Declarative

  2. Imperative

  3. Assertive

  4. Optative

  5. Exhortative

  6. Descriptive

  7. Expository

  8. Complex

  9. Polite

  10. Rude

Таким образом, даже на одни и те же вопросы ИИ-учитель всегда дает разный ответ, что вносит разнообразие во время общения.

Код консольной программы ИИ-учителя можно посмотреть здесь. Код библиотеки работающей с OpenAI API можно посмотреть здесь.

Ну и наконец, пример взаимодействия с этой программой, которая заменяет учителя английского языка:

Please enter a topic of the lesson:

hotel

Words of lesson:

  1. Lodging

  2. Accommodation

  3. Suite

  4. Room

  5. Reception

  6. Concierge

  7. Check-in

  8. Check-out

  9. Amenities

  10. Restaurant

  11. Bar

  12. Pool

  13. Spa

  14. Gym

  15. Valet

  16. Bellhop

Do you know all these words? Say: Yes or write unknown words comma separated:

bellhop, valet

Bellhop

A bellhop is a hotel employee who assists guests with their luggage and other needs. They are usually the first person a guest sees when they arrive at the hotel. Example 1: The bellhop carried our luggage to our room in the hotel. Example 2: "Hey bellhop, why are you so slow? Hurry up and get my bags to my room!"

Valet

Valet is a service offered by some hotels where a guest can have their car parked and retrieved by a hotel employee. Example 1: The hotel valet was very helpful in parking our car. Example 2: "If you can't do your job as a valet in this hotel, then you should find another job."

What type of establishment typically offers a variety of food and beverages for customers to enjoy?

I think it is restraunt.

I think it is restaurant. < grammar fixes

What is the process for check-in at a lodging establishment?

You need show a passport and student card. Is it correct?

You need to show a passport and student card. Is it correct? < grammar fixes

Yes, it is correct that you need to show a passport and student card in order to prove your identity and student status. Depending on the situation, you may need to provide additional documents such as a birth certificate or proof of address.

What kind of lodging would you prefer?

I prefer room with toulet and shower. If I visit hotel with wife then I prefer one big bad for two.

I prefer room with toilet and shower. If I visit hotel with wife then I prefer one big bad for two. < grammar fixes

What is the average wait time at the reception desk?

Usually it could take not more 5 minutes.

Usually it could take not more than 5 minutes. < grammar fixes

What services does a concierge provide?

You could ask a concierge call you at 7:00 am to wake you tommorow.

You could ask a concierge to call you at 7:00 am to wake you tomorrow. < grammar fixes

What kind of accommodation can you find when you travel?

When I travel I usualy take apartmant in hotel.

When I travel I usually take an apartment in a hotel. < grammar fixes

Do you have a swimming pool at your accommodation?

No We do not have swimming pool at the hotel.

No, we do not have a swimming pool at the hotel. < grammar fixes

Комментарии (28)


  1. PrinceKorwin
    24.01.2023 20:05

    Спасибо за ссылки на код. Хочу себе сделать что-то подобное. В вашем коде смутило обилие . unwrap (). Это нормально? Тем более для библиотеки.


    1. igumnov Автор
      24.01.2023 20:11

      Не должна либа сваливаться в panic. Согласен с Вами. Просто хотел быстрее написать.


      1. igumnov Автор
        27.01.2023 11:32

        Убрал все unwrap

        Теперь вот какая проблема, код стал тяжело читаем:

            let request_result = serde_json::to_string(&request);
        
            match request_result {
                Ok(request_string) => {
                    let resp_result = client.post("https://api.openai.com/v1/completions")
                        .timeout(Duration::from_secs(30))
                        .insert_header(("Content-Type", "application/json"))
                        .insert_header(("Authorization", format!("Bearer {}", api_key)))
                        .send_body(request_string)
                        .await;
                    match resp_result {
                        Ok(mut resp) => {
                            let bytes_result = resp.body().await;
                            match bytes_result {
                                Ok(bytes) => {
                                    let string_result = String::from_utf8(bytes.to_vec());
                                    match string_result {
                                        Ok(string) => {
                                            let parse_result: Result<CompletionsResponse, serde_json::Error> = serde_json::from_str(&string);
                                            match parse_result {
                                                Ok(response) => Ok(response),
                                                Err(e) => Err(e.to_string()),
                                            }
                                        },
                                        Err(e) => Err(e.to_string())
                                    }
                                },
                                Err(e) => Err(e.to_string())
                            }
        
                        },
                        Err(e) => Err(e.to_string())
                    }
                },
                Err(e) => Err(e.to_string()),
            }
        
        

        Может есть другой способ как красиво написать что бы читабельность была нормальная?

        Ну и я что-то поленился заводить свои Error и просто возвращаю в случае ошибки String с текстом ошибки, наверное это не очень хорошо.

         -> Result<CompletionsResponse, String> 


    1. lain8dono
      24.01.2023 20:35
      +3

      Это нормально?

      Для кода, написанного на скорую руку вполне. Но лучше по быстрому обернуть в thiserror.


  1. aborouhin
    24.01.2023 22:24

    А big bad на big bed не исправило :)

    P.S. Да и с артиклями беда.


    1. igumnov Автор
      25.01.2023 04:48

      Пока что реализация и интерфейс OpenAI API не позволяют всегда получить правильный ответ, но в большинстве случаев выглядит приемлемо.


  1. lair
    24.01.2023 22:26

    Ну и наконец, пример взаимодействия с этой программой, которая заменяет учителя английского языка:

    Пытается заменить, но не заменяет. Разбор ошибок нужен?


    1. igumnov Автор
      25.01.2023 04:49
      +1

      Ага. Это прототип. Первая версия. Написал всего за пару вечеров.


      1. lair
        25.01.2023 04:55

        Вы сам не видите, что ваш "учитель" (а) пропускает очень много языковых ошибок, и (б) вообще не проверяет текст на смысл?


        1. igumnov Автор
          25.01.2023 05:20

          Я вижу. Вы тоже. Что дальше?


          1. lair
            25.01.2023 05:21

            А дальше, наверное, стоит задуматься, что ваша программа не выполняет того, что вы заявили - она не заменяет учителя английского языка.


            1. igumnov Автор
              25.01.2023 05:23
              +2

              Если вы попытаетесь догнать электричку. Если не догоните, то хотя бы согреетесь.


              1. lair
                25.01.2023 05:24
                -1

                ...или упадете без сил в сугроб, где и замерзнете насмерть.

                Аналогии врут.


                1. igumnov Автор
                  25.01.2023 05:24

                  Все аналогии ложные.


                  1. lair
                    25.01.2023 05:25

                    Так может не стоит к ним прибегать тогда?

                    (как и не стоит делать ложных заявлений о возможностях вашей программы)


                    1. igumnov Автор
                      25.01.2023 05:27

                      Добавлю в название статьи слово "прототип", дабы успокоить "отца" перфекционизма.


                      1. lair
                        25.01.2023 05:33
                        -1

                        Перфекционизм - это когда что-то сделано хорошо, но могло бы быть лучше. А в вашем случае (с точки зрения обучения языку) сделано плохо.


                      1. igumnov Автор
                        25.01.2023 05:35

                        Согласен.


  1. lair
    24.01.2023 22:44

    реализация полноценного сервиса требует [...] разработки веб-версии ИИ-учителя [..] Я, конечно, могу выполнить все эти задачи

    Воу. Вы правда искренне считаете, что в одиночку можете сделать ИИ, который заменяет учителя иностранного языка?


    1. igumnov Автор
      25.01.2023 04:50

      Нет


      1. lair
        25.01.2023 04:53

        Тогда почему вы пишете "я, конечно, могу выполнить все эти задачи"?


        1. igumnov Автор
          25.01.2023 05:17

          Потому что я могу, но зачем мне тратить пару лет на это? Или больше.


          1. lair
            25.01.2023 05:19

            Гм, не сходится.

            Сначала вы говорите, что можете. Потом в ответ на прямой вопрос говорите, что нет. А теперь снова говорите, что можете.

            Так можете, или нет?


            1. igumnov Автор
              25.01.2023 05:23

              Красивый троллинг :)


              1. Hardcoin
                27.01.2023 04:34

                А в чем троллинг? Вы действительно отвечаете, что можете, а потом, что не можете. Как-то странно.


  1. KValery
    25.01.2023 04:51

    Идея для новой фичи: пользователь задаёт уровень знания языка, тему конкретную или без темы. Далее нужно сделать интеграцию чата с голосовым помощником, чтобы реализовать следующий процесс имитации разговорного диалога: пользователь говорит фразу голосовому помощнику, тот ее распознает и отправляет в gpt, gpt выдает текстовый ответ, голосовой помощник его озвучивает.

    Я протестировал такое взаимодействие пока только на уровне текста и это уже супер для имитации реального диалога. При этом я заранее задал условие, чтобы на все мои ответы gpt отвечал только ОК, если ответ был написан правильно. И NO плюс верное написание, если мой ответ был написан неверно.

    Если же будет добавлена функция голосовая, то это будет аналог живого устного общения, которого обычно очень не хватает при обучении языку.


    1. igumnov Автор
      25.01.2023 04:53

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


  1. leonidv
    25.01.2023 09:57

    Исходя из тэга Rust и Open API в названии, я ожидал прочитать про создание сервиса на Rust. Как мне кажется, тэг Rust здесь лишний.